From 2036e5c3b03d7671d061a6db7ebf417303a7abf0 Mon Sep 17 00:00:00 2001 From: Andrew Risse Date: Wed, 3 Apr 2024 12:49:02 -0600 Subject: [PATCH 01/10] chore: bring ui into monorepo --- .github/dependabot.yml | 11 + packages/ui/chart/Chart.yaml | 24 + packages/ui/chart/templates/namespace.yaml | 4 + packages/ui/chart/templates/uds-package.yaml | 26 + .../ui/chart/templates/ui/deployment.yaml | 45 + packages/ui/chart/templates/ui/service.yaml | 25 + packages/ui/chart/values.yaml | 2 + packages/ui/zarf-config.yaml | 7 + packages/ui/zarf.yaml | 74 + src/leapfrogai_ui/.dockerignore | 34 + src/leapfrogai_ui/.env.example | 21 + src/leapfrogai_ui/.env.public | 9 + src/leapfrogai_ui/.eslintignore | 13 + src/leapfrogai_ui/.eslintrc.cjs | 31 + .../.github/workflows/ISSUE_TEMPLATE/bug.md | 17 + .../workflows/ISSUE_TEMPLATE/content.md | 11 + .../workflows/ISSUE_TEMPLATE/feature.md | 11 + .../.github/workflows/release.yaml | 49 + src/leapfrogai_ui/.gitignore | 23 + src/leapfrogai_ui/.husky/commit-msg | 1 + src/leapfrogai_ui/.husky/install.mjs | 6 + src/leapfrogai_ui/.husky/pre-commit | 10 + src/leapfrogai_ui/.npmrc | 1 + src/leapfrogai_ui/.prettierignore | 6 + src/leapfrogai_ui/.prettierrc | 8 + src/leapfrogai_ui/Dockerfile | 24 + src/leapfrogai_ui/Makefile | 7 + src/leapfrogai_ui/README.md | 193 + src/leapfrogai_ui/commitlint.config.js | 1 + src/leapfrogai_ui/package-lock.json | 8043 +++++++++++++++++ src/leapfrogai_ui/package.json | 74 + src/leapfrogai_ui/playwright.config.ts | 51 + src/leapfrogai_ui/src/app.d.ts | 24 + src/leapfrogai_ui/src/app.html | 12 + src/leapfrogai_ui/src/hooks.server.ts | 46 + .../src/lib/assets/DefenseUnicorns.png | Bin 0 -> 15824 bytes src/leapfrogai_ui/src/lib/assets/Doug.png | Bin 0 -> 6395 bytes .../src/lib/assets/LeapfrogAI.png | Bin 0 -> 127778 bytes src/leapfrogai_ui/src/lib/assets/frog.png | Bin 0 -> 11024 bytes .../src/lib/components/ChatSidebar.svelte | 325 + .../src/lib/components/ChatSidebar.test.ts | 309 + .../src/lib/components/PoweredByDU.svelte | 28 + .../src/lib/components/Toasts.svelte | 34 + src/leapfrogai_ui/src/lib/components/index.ts | 3 + src/leapfrogai_ui/src/lib/constants/index.ts | 1 + .../src/lib/helpers/dates.test.ts | 178 + src/leapfrogai_ui/src/lib/helpers/dates.ts | 181 + src/leapfrogai_ui/src/lib/helpers/index.ts | 1 + src/leapfrogai_ui/src/lib/mocks/chat-mocks.ts | 100 + src/leapfrogai_ui/src/lib/mocks/svelte.ts | 35 + .../src/lib/stores/conversations.ts | 100 + src/leapfrogai_ui/src/lib/stores/index.ts | 2 + src/leapfrogai_ui/src/lib/stores/toast.ts | 48 + src/leapfrogai_ui/src/lib/supabaseClient.ts | 4 + .../src/lib/types/conversations.d.ts | 29 + src/leapfrogai_ui/src/lib/types/toast.d.ts | 6 + .../src/routes/+layout.server.ts | 7 + src/leapfrogai_ui/src/routes/+layout.svelte | 31 + src/leapfrogai_ui/src/routes/+layout.ts | 29 + src/leapfrogai_ui/src/routes/+page.server.ts | 13 + src/leapfrogai_ui/src/routes/+page.svelte | 48 + .../src/routes/api/chat/+server.ts | 53 + .../src/routes/api/chat/server.test.ts | 27 + .../api/conversations/delete/+server.ts | 18 + .../routes/api/conversations/new/+server.ts | 35 + .../api/conversations/update/label/+server.ts | 21 + .../src/routes/api/messages/new/+server.ts | 27 + .../src/routes/auth/+page.server.ts | 12 + .../src/routes/auth/callback/+server.ts | 12 + .../chat/[[conversation_id]]/+layout.svelte | 75 + .../chat/[[conversation_id]]/+page.server.ts | 34 + .../chat/[[conversation_id]]/+page.svelte | 202 + .../ChatPageWithToast.test.svelte | 9 + .../chat/[[conversation_id]]/chatpage.test.ts | 176 + src/leapfrogai_ui/src/schemas/chat.ts | 10 + src/leapfrogai_ui/src/styles/main.scss | 10 + .../src/testUtils/fakeData/index.ts | 78 + src/leapfrogai_ui/static/favicon.png | Bin 0 -> 10974 bytes src/leapfrogai_ui/supabase/.gitignore | 4 + src/leapfrogai_ui/supabase/config.toml | 169 + ...40322174519_create_conversations_table.sql | 6 + .../20240322174700_create_messages_table.sql | 8 + .../20240322174734_create_profiles_table.sql | 11 + ...40322174754_create_role_level_security.sql | 46 + ...0240322174913_create_function_new_user.sql | 17 + src/leapfrogai_ui/supabase/seed.sql | 116 + src/leapfrogai_ui/svelte.config.js | 25 + src/leapfrogai_ui/tests/api.test.ts | 19 + src/leapfrogai_ui/tests/auth.setup.ts | 45 + src/leapfrogai_ui/tests/chat.test.ts | 54 + src/leapfrogai_ui/tests/helpers.ts | 15 + src/leapfrogai_ui/tests/logout.test.ts | 12 + src/leapfrogai_ui/tests/sidebar.test.ts | 73 + src/leapfrogai_ui/tsconfig.json | 19 + src/leapfrogai_ui/vite.config.ts | 20 + src/leapfrogai_ui/vitest-setup.ts | 99 + 96 files changed, 12013 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 packages/ui/chart/Chart.yaml create mode 100644 packages/ui/chart/templates/namespace.yaml create mode 100644 packages/ui/chart/templates/uds-package.yaml create mode 100644 packages/ui/chart/templates/ui/deployment.yaml create mode 100644 packages/ui/chart/templates/ui/service.yaml create mode 100644 packages/ui/chart/values.yaml create mode 100644 packages/ui/zarf-config.yaml create mode 100644 packages/ui/zarf.yaml create mode 100644 src/leapfrogai_ui/.dockerignore create mode 100644 src/leapfrogai_ui/.env.example create mode 100644 src/leapfrogai_ui/.env.public create mode 100644 src/leapfrogai_ui/.eslintignore create mode 100644 src/leapfrogai_ui/.eslintrc.cjs create mode 100644 src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/bug.md create mode 100644 src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/content.md create mode 100644 src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/feature.md create mode 100644 src/leapfrogai_ui/.github/workflows/release.yaml create mode 100644 src/leapfrogai_ui/.gitignore create mode 100644 src/leapfrogai_ui/.husky/commit-msg create mode 100644 src/leapfrogai_ui/.husky/install.mjs create mode 100644 src/leapfrogai_ui/.husky/pre-commit create mode 100644 src/leapfrogai_ui/.npmrc create mode 100644 src/leapfrogai_ui/.prettierignore create mode 100644 src/leapfrogai_ui/.prettierrc create mode 100644 src/leapfrogai_ui/Dockerfile create mode 100644 src/leapfrogai_ui/Makefile create mode 100644 src/leapfrogai_ui/README.md create mode 100644 src/leapfrogai_ui/commitlint.config.js create mode 100644 src/leapfrogai_ui/package-lock.json create mode 100644 src/leapfrogai_ui/package.json create mode 100644 src/leapfrogai_ui/playwright.config.ts create mode 100644 src/leapfrogai_ui/src/app.d.ts create mode 100644 src/leapfrogai_ui/src/app.html create mode 100644 src/leapfrogai_ui/src/hooks.server.ts create mode 100644 src/leapfrogai_ui/src/lib/assets/DefenseUnicorns.png create mode 100644 src/leapfrogai_ui/src/lib/assets/Doug.png create mode 100644 src/leapfrogai_ui/src/lib/assets/LeapfrogAI.png create mode 100644 src/leapfrogai_ui/src/lib/assets/frog.png create mode 100644 src/leapfrogai_ui/src/lib/components/ChatSidebar.svelte create mode 100644 src/leapfrogai_ui/src/lib/components/ChatSidebar.test.ts create mode 100644 src/leapfrogai_ui/src/lib/components/PoweredByDU.svelte create mode 100644 src/leapfrogai_ui/src/lib/components/Toasts.svelte create mode 100644 src/leapfrogai_ui/src/lib/components/index.ts create mode 100644 src/leapfrogai_ui/src/lib/constants/index.ts create mode 100644 src/leapfrogai_ui/src/lib/helpers/dates.test.ts create mode 100644 src/leapfrogai_ui/src/lib/helpers/dates.ts create mode 100644 src/leapfrogai_ui/src/lib/helpers/index.ts create mode 100644 src/leapfrogai_ui/src/lib/mocks/chat-mocks.ts create mode 100644 src/leapfrogai_ui/src/lib/mocks/svelte.ts create mode 100644 src/leapfrogai_ui/src/lib/stores/conversations.ts create mode 100644 src/leapfrogai_ui/src/lib/stores/index.ts create mode 100644 src/leapfrogai_ui/src/lib/stores/toast.ts create mode 100644 src/leapfrogai_ui/src/lib/supabaseClient.ts create mode 100644 src/leapfrogai_ui/src/lib/types/conversations.d.ts create mode 100644 src/leapfrogai_ui/src/lib/types/toast.d.ts create mode 100644 src/leapfrogai_ui/src/routes/+layout.server.ts create mode 100644 src/leapfrogai_ui/src/routes/+layout.svelte create mode 100644 src/leapfrogai_ui/src/routes/+layout.ts create mode 100644 src/leapfrogai_ui/src/routes/+page.server.ts create mode 100644 src/leapfrogai_ui/src/routes/+page.svelte create mode 100644 src/leapfrogai_ui/src/routes/api/chat/+server.ts create mode 100644 src/leapfrogai_ui/src/routes/api/chat/server.test.ts create mode 100644 src/leapfrogai_ui/src/routes/api/conversations/delete/+server.ts create mode 100644 src/leapfrogai_ui/src/routes/api/conversations/new/+server.ts create mode 100644 src/leapfrogai_ui/src/routes/api/conversations/update/label/+server.ts create mode 100644 src/leapfrogai_ui/src/routes/api/messages/new/+server.ts create mode 100644 src/leapfrogai_ui/src/routes/auth/+page.server.ts create mode 100644 src/leapfrogai_ui/src/routes/auth/callback/+server.ts create mode 100644 src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+layout.svelte create mode 100644 src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+page.server.ts create mode 100644 src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+page.svelte create mode 100644 src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/ChatPageWithToast.test.svelte create mode 100644 src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/chatpage.test.ts create mode 100644 src/leapfrogai_ui/src/schemas/chat.ts create mode 100644 src/leapfrogai_ui/src/styles/main.scss create mode 100644 src/leapfrogai_ui/src/testUtils/fakeData/index.ts create mode 100644 src/leapfrogai_ui/static/favicon.png create mode 100644 src/leapfrogai_ui/supabase/.gitignore create mode 100644 src/leapfrogai_ui/supabase/config.toml create mode 100644 src/leapfrogai_ui/supabase/migrations/20240322174519_create_conversations_table.sql create mode 100644 src/leapfrogai_ui/supabase/migrations/20240322174700_create_messages_table.sql create mode 100644 src/leapfrogai_ui/supabase/migrations/20240322174734_create_profiles_table.sql create mode 100644 src/leapfrogai_ui/supabase/migrations/20240322174754_create_role_level_security.sql create mode 100644 src/leapfrogai_ui/supabase/migrations/20240322174913_create_function_new_user.sql create mode 100644 src/leapfrogai_ui/supabase/seed.sql create mode 100644 src/leapfrogai_ui/svelte.config.js create mode 100644 src/leapfrogai_ui/tests/api.test.ts create mode 100644 src/leapfrogai_ui/tests/auth.setup.ts create mode 100644 src/leapfrogai_ui/tests/chat.test.ts create mode 100644 src/leapfrogai_ui/tests/helpers.ts create mode 100644 src/leapfrogai_ui/tests/logout.test.ts create mode 100644 src/leapfrogai_ui/tests/sidebar.test.ts create mode 100644 src/leapfrogai_ui/tsconfig.json create mode 100644 src/leapfrogai_ui/vite.config.ts create mode 100644 src/leapfrogai_ui/vitest-setup.ts diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..7b9c0481e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: 'npm' # See documentation for possible values + directory: '/src/leapfrogai_ui' # Location of package manifests + schedule: + interval: 'weekly' diff --git a/packages/ui/chart/Chart.yaml b/packages/ui/chart/Chart.yaml new file mode 100644 index 000000000..8542d0f8b --- /dev/null +++ b/packages/ui/chart/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: leapfrogai-ui +description: UI to interact with LFAI tools + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: '0.1.7' diff --git a/packages/ui/chart/templates/namespace.yaml b/packages/ui/chart/templates/namespace.yaml new file mode 100644 index 000000000..0172d6405 --- /dev/null +++ b/packages/ui/chart/templates/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: leapfrogai diff --git a/packages/ui/chart/templates/uds-package.yaml b/packages/ui/chart/templates/uds-package.yaml new file mode 100644 index 000000000..5c1182120 --- /dev/null +++ b/packages/ui/chart/templates/uds-package.yaml @@ -0,0 +1,26 @@ +apiVersion: uds.dev/v1alpha1 +kind: Package +metadata: + name: leapfrogai-ui + namespace: {{ .Release.Namespace }} +spec: + network: + expose: + - service: leapfrogai-ui + podLabels: + app: leapfrogai-ui + host: {{ .Values.package.host }} + gateway: tenant + port: 3000 + + allow: + - direction: Ingress + remoteGenerated: Anywhere + + - direction: Egress + remoteGenerated: Anywhere + + - direction: Egress + podLabels: + app: leapfrogai-ui + remoteGenerated: Anywhere diff --git a/packages/ui/chart/templates/ui/deployment.yaml b/packages/ui/chart/templates/ui/deployment.yaml new file mode 100644 index 000000000..23052a9c1 --- /dev/null +++ b/packages/ui/chart/templates/ui/deployment.yaml @@ -0,0 +1,45 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: leapfrogai-ui + namespace: leapfrogai +spec: + selector: + matchLabels: + app: leapfrogai-ui + replicas: 1 + template: + metadata: + labels: + app: leapfrogai-ui + spec: + containers: + - name: leapfrogai-ui + image: 'ghcr.io/defenseunicorns/leapfrogai/leapfrogai-ui:###ZARF_CONST_IMAGE_VERSION###' + ports: + - containerPort: 3000 + env: + - name: PUBLIC_LEAPFROGAI_API_BASE_URL + value: '###ZARF_VAR_LEAPFROGAI_API_BASE_URL###' + - name: ORIGIN + value: '###ZARF_VAR_DOMAIN###' + - name: PUBLIC_DEFAULT_MODEL + value: '###ZARF_VAR_MODEL###' + - name: PUBLIC_DEFAULT_SYSTEM_PROMPT + value: '###ZARF_VAR_SYSTEM_PROMPT###' + - name: PUBLIC_DEFAULT_TEMPERATURE + value: '###ZARF_VAR_TEMPERATURE###' + - name: LEAPFROGAI_API_KEY + value: '###ZARF_VAR_LEAPFROGAI_API_KEY###' + - name: PUBLIC_SUPABASE_URL + value: '###ZARF_VAR_SUPABASE_URL###' + - name: PUBLIC_SUPABASE_ANON_KEY + value: '###ZARF_VAR_SUPABASE_ANON_KEY###' + + resources: + requests: + memory: '5Gi' + cpu: '500m' + limits: + memory: '5Gi' + cpu: '1000m' diff --git a/packages/ui/chart/templates/ui/service.yaml b/packages/ui/chart/templates/ui/service.yaml new file mode 100644 index 000000000..2e7ef8dda --- /dev/null +++ b/packages/ui/chart/templates/ui/service.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: leapfrogai-ui + namespace: leapfrogai +--- +apiVersion: v1 +kind: Service +metadata: + name: leapfrogai-ui + namespace: leapfrogai + labels: + app: leapfrogai-ui + service: leapfrogai-ui + zarf.dev/connect-name: leapfrogai-ui + annotations: + zarf.dev/connect-description: 'The LeapfrogAI UI' +spec: + selector: + app: leapfrogai-ui + ports: + - name: http + port: 3000 + targetPort: 3000 + protocol: TCP diff --git a/packages/ui/chart/values.yaml b/packages/ui/chart/values.yaml new file mode 100644 index 000000000..a0d7e4b40 --- /dev/null +++ b/packages/ui/chart/values.yaml @@ -0,0 +1,2 @@ +package: + host: lfaiui diff --git a/packages/ui/zarf-config.yaml b/packages/ui/zarf-config.yaml new file mode 100644 index 000000000..c9791289e --- /dev/null +++ b/packages/ui/zarf-config.yaml @@ -0,0 +1,7 @@ +package: + create: + set: + image_repository: 'ghcr.io/defenseunicorns/leapfrogai/leapfrogai-ui' + image_version: 0.1.7 + name: leapfrogai-ui + max_package_size: '1000000000' diff --git a/packages/ui/zarf.yaml b/packages/ui/zarf.yaml new file mode 100644 index 000000000..344ce9dab --- /dev/null +++ b/packages/ui/zarf.yaml @@ -0,0 +1,74 @@ +kind: ZarfPackageConfig +metadata: + name: '###ZARF_PKG_TMPL_NAME###' + version: '###ZARF_PKG_TMPL_IMAGE_VERSION###' + description: > + A UI for LeapfrogAI + +constants: + - name: IMAGE_VERSION + value: '###ZARF_PKG_TMPL_IMAGE_VERSION###' + - name: NAME + value: '###ZARF_PKG_TMPL_NAME###' + +variables: + - name: LEAPFROGAI_API_BASE_URL #LEAPFROGAI_API_BASE_URL + description: The base URL for the LeapfrogAI API + default: http://api.leapfrogai.svc.cluster.local:8080/openai/v1 + prompt: true + sensitive: true + - name: LEAPFROGAI_API_KEY + description: The api key the LeapfrogAI API (can be left default for local development) + default: my-test-key + prompt: true + sensitive: true + - name: DOMAIN + description: The domain to use for the application, Istio-ingress configuration + default: https://lfaiui.uds.dev + prompt: true + sensitive: true + - name: MODEL + description: The default LLM model to use for chat and summarization + default: vllm + prompt: true + sensitive: false + - name: SYSTEM_PROMPT + description: The default system prompt to use for the LLM + default: 'You are a helpful AI assistant created by Defense Unicorns.' + prompt: true + sensitive: false + - name: TEMPERATURE + description: The default temperature for the LLM + default: '0.1' + prompt: true + sensitive: false + - name: SUPABASE_URL + description: URL for supabase + default: 'http://supabase.leapfrogai.svc.cluster.local:8080' + prompt: true + sensitive: false + - name: SUPABASE_ANON_KEY + description: Public key for Supabase + default: '' + prompt: true + sensitive: false + +components: + - name: leapfrogai-ui + required: true + charts: + - name: leapfrogai-ui + namespace: leapfrogai + localPath: chart + version: '###ZARF_PKG_TMPL_IMAGE_VERSION###' + images: + - '###ZARF_PKG_TMPL_IMAGE_REPOSITORY###:###ZARF_PKG_TMPL_IMAGE_VERSION###' + actions: + onDeploy: + after: + - wait: + cluster: + kind: Deployment + name: leapfrogai-ui + namespace: leapfrogai + condition: Available diff --git a/src/leapfrogai_ui/.dockerignore b/src/leapfrogai_ui/.dockerignore new file mode 100644 index 000000000..6e095c184 --- /dev/null +++ b/src/leapfrogai_ui/.dockerignore @@ -0,0 +1,34 @@ +.DS_Store +node_modules +/.svelte-kit +/build +/package +**/.env +!.env.public +vite.config.js.timestamp-* +vite.config.ts.timestamp-* + +Dockerfile +.dockerignore +.git +.gitignore +.gitattributes +README.md +.npmrc +.prettierrc +.eslintrc.cjs +.editorconfig +.vscode +.idea +build +package + + +*.tar.zst +zarf-sbom/ + + +playwright/.auth + + +supabase/ \ No newline at end of file diff --git a/src/leapfrogai_ui/.env.example b/src/leapfrogai_ui/.env.example new file mode 100644 index 000000000..3eb802d4f --- /dev/null +++ b/src/leapfrogai_ui/.env.example @@ -0,0 +1,21 @@ +# PUBLIC STATIC +PUBLIC_DEFAULT_TEMPERATURE=0.1 +PUBLIC_DEFAULT_SYSTEM_PROMPT="You are a helpful AI assistant created by Defense Unicorns." +PUBLIC_DEFAULT_MODEL=vllm +PUBLIC_LEAPFROGAI_API_BASE_URL=https://leapfrogai-api.uds.dev/openai/v1 + +# PUBLIC DYNAMIC +PUBLIC_SUPABASE_URL=http://localhost:54321 +PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0 + +# PRIVATE DYNAMIC +LEAPFROGAI_API_KEY=my-test-key + +# PLAYWRIGHT +USERNAME=user1@test.com +PASSWORD= + +# SUPABASE AUTH (when running Supabase Locally) +SUPABASE_AUTH_KEYCLOAK_CLIENT_ID=lfaiui +SUPABASE_AUTH_KEYCLOAK_SECRET= +SUPABASE_AUTH_EXTERNAL_KEYCLOAK_URL=https://keycloak.admin.uds.dev/realms/uds diff --git a/src/leapfrogai_ui/.env.public b/src/leapfrogai_ui/.env.public new file mode 100644 index 000000000..1870f8ac6 --- /dev/null +++ b/src/leapfrogai_ui/.env.public @@ -0,0 +1,9 @@ +# THESE VARIABLES ARE PUBLIC STATIC VARIABLES COPIED INTO THE DOCKERFILE AT BUILD TIME +# THIS FILE IS COMMITTED TO GIT +# !!!!!! DO NOT INCLUDE PRIVATE VARIABLES IN THIS FILE !!!!! +PUBLIC_DEFAULT_TEMPERATURE=0.1 +PUBLIC_DEFAULT_SYSTEM_PROMPT="You are a helpful AI assistant created by Defense Unicorns." +PUBLIC_DEFAULT_MODEL=vllm +PUBLIC_LEAPFROGAI_API_BASE_URL=http://api.leapfrogai.svc.cluster.local:8080/openai/v1 + +# DO NOT INCLUDE PRIVATE VARIABLES IN THIS FILE \ No newline at end of file diff --git a/src/leapfrogai_ui/.eslintignore b/src/leapfrogai_ui/.eslintignore new file mode 100644 index 000000000..38972655f --- /dev/null +++ b/src/leapfrogai_ui/.eslintignore @@ -0,0 +1,13 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example + +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/src/leapfrogai_ui/.eslintrc.cjs b/src/leapfrogai_ui/.eslintrc.cjs new file mode 100644 index 000000000..0b757582c --- /dev/null +++ b/src/leapfrogai_ui/.eslintrc.cjs @@ -0,0 +1,31 @@ +/** @type { import("eslint").Linter.Config } */ +module.exports = { + root: true, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:svelte/recommended', + 'prettier' + ], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + parserOptions: { + sourceType: 'module', + ecmaVersion: 2020, + extraFileExtensions: ['.svelte'] + }, + env: { + browser: true, + es2017: true, + node: true + }, + overrides: [ + { + files: ['*.svelte'], + parser: 'svelte-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser' + } + } + ] +}; diff --git a/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/bug.md b/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/bug.md new file mode 100644 index 000000000..8b17cd6be --- /dev/null +++ b/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/bug.md @@ -0,0 +1,17 @@ +--- +name: Bug report +about: Something isn't working as expected +title: '' +labels: ['bug', 'needs-triage'] +assignees: '' +--- + +**Describe the bug** + +**URL Where bug was discovered** + +**Screenshots** + +**Browser and Device** + +**Additional context** diff --git a/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/content.md b/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/content.md new file mode 100644 index 000000000..24038a7bd --- /dev/null +++ b/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/content.md @@ -0,0 +1,11 @@ +--- +name: Content Request +about: Changes to content, styling, layout, or images +title: '' +labels: ['content', 'needs-triage'] +assignees: '' +--- + +**Description** + +**Additional context** diff --git a/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/feature.md b/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/feature.md new file mode 100644 index 000000000..e4ae0bcc9 --- /dev/null +++ b/src/leapfrogai_ui/.github/workflows/ISSUE_TEMPLATE/feature.md @@ -0,0 +1,11 @@ +--- +name: Feature Request +about: Something new or better to add +title: '' +labels: ['feature', 'needs-triage'] +assignees: '' +--- + +**Describe the Feature** + +**Additional context** diff --git a/src/leapfrogai_ui/.github/workflows/release.yaml b/src/leapfrogai_ui/.github/workflows/release.yaml new file mode 100644 index 000000000..31a5364ef --- /dev/null +++ b/src/leapfrogai_ui/.github/workflows/release.yaml @@ -0,0 +1,49 @@ +name: Release Artifacts + +on: + push: + tags: + - '*.*.*' + - dev + +jobs: + build-and-publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Version + id: get_version + uses: battila7/get-version-action@90eb8fc70f6dfcf3f9b95ed8f164d2c05038e729 # v2.2.1 + + - name: Login to GitHub Container Registry + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@0d103c3126aa41d772a8362f6aa67afac040f80c # v3.1.0 + + - name: Build Images + run: | + docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/defenseunicorns/leapfrogai/leapfrogai-ui:${{ steps.get_version.outputs.version-without-v }} --push . + + - name: Install Zarf + uses: defenseunicorns/setup-zarf@f95763914e20e493bb5d45d63e30e17138f981d6 # v1.0.0 + + - name: Build Zarf Package + run: | + zarf package create . --set=PACKAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture amd64 --confirm + zarf package create . --set=PACKAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --set=IMAGE_VERSION=${{ steps.get_version.outputs.version-without-v }} --architecture arm64 --confirm + + - name: Publish Zarf Package + run: | + zarf package publish zarf-package-leapfrogai-ui-amd64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai + zarf package publish zarf-package-leapfrogai-ui-arm64-${{ steps.get_version.outputs.version-without-v }}.tar.zst oci://ghcr.io/defenseunicorns/packages/leapfrogai diff --git a/src/leapfrogai_ui/.gitignore b/src/leapfrogai_ui/.gitignore new file mode 100644 index 000000000..26d0b926b --- /dev/null +++ b/src/leapfrogai_ui/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example +!.env.public +vite.config.js.timestamp-* +vite.config.ts.timestamp-* + +*.tar.zst +zarf-sbom/ + +# IntelliJ +.idea/workspace.xml +.idea/statistics.xml +.idea/shelf/ + + +playwright/.auth +test-results/ \ No newline at end of file diff --git a/src/leapfrogai_ui/.husky/commit-msg b/src/leapfrogai_ui/.husky/commit-msg new file mode 100644 index 000000000..0a4b97de5 --- /dev/null +++ b/src/leapfrogai_ui/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --edit $1 diff --git a/src/leapfrogai_ui/.husky/install.mjs b/src/leapfrogai_ui/.husky/install.mjs new file mode 100644 index 000000000..4e9a0823b --- /dev/null +++ b/src/leapfrogai_ui/.husky/install.mjs @@ -0,0 +1,6 @@ +// Skip Husky install in production and CI +if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') { + process.exit(0); +} +const husky = (await import('husky')).default; +console.log(husky()); diff --git a/src/leapfrogai_ui/.husky/pre-commit b/src/leapfrogai_ui/.husky/pre-commit new file mode 100644 index 000000000..f99ff0051 --- /dev/null +++ b/src/leapfrogai_ui/.husky/pre-commit @@ -0,0 +1,10 @@ +docker run -v "$(pwd):/workdir" -i --rm trufflesecurity/trufflehog:latest git file:///workdir --only-verified --fail + +npm run format +npm run lint + +git add . + +if [ "$SKIP_TEST" != "true" ]; then + npm run test +fi \ No newline at end of file diff --git a/src/leapfrogai_ui/.npmrc b/src/leapfrogai_ui/.npmrc new file mode 100644 index 000000000..b6f27f135 --- /dev/null +++ b/src/leapfrogai_ui/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/src/leapfrogai_ui/.prettierignore b/src/leapfrogai_ui/.prettierignore new file mode 100644 index 000000000..3bdee0e3b --- /dev/null +++ b/src/leapfrogai_ui/.prettierignore @@ -0,0 +1,6 @@ +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock + +../../packages/ui/chart/ \ No newline at end of file diff --git a/src/leapfrogai_ui/.prettierrc b/src/leapfrogai_ui/.prettierrc new file mode 100644 index 000000000..95730232b --- /dev/null +++ b/src/leapfrogai_ui/.prettierrc @@ -0,0 +1,8 @@ +{ + "useTabs": true, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/src/leapfrogai_ui/Dockerfile b/src/leapfrogai_ui/Dockerfile new file mode 100644 index 000000000..9615cce6f --- /dev/null +++ b/src/leapfrogai_ui/Dockerfile @@ -0,0 +1,24 @@ +FROM node:18-alpine AS builder +WORKDIR /app +COPY package.json ./ +COPY package-lock.json ./ +RUN npm ci +COPY . . +ENV NODE_ENV=production +RUN cp .env.public .env +RUN npm run build +RUN npm prune + +FROM cgr.dev/chainguard/node:latest + +WORKDIR /app +COPY --chown=node:node --from=builder /app/build build/ +COPY --chown=node:node --from=builder /app/node_modules node_modules/ +COPY --chown=node:node package.json . +EXPOSE 3000 +ENV NODE_ENV=production +# Disable request size limit +ENV BODY_SIZE_LIMIT=Infinity +ENV PROTOCOL_HEADER=x-forwarded-proto +ENV HOST_HEADER=x-forwarded-host +CMD ["build"] \ No newline at end of file diff --git a/src/leapfrogai_ui/Makefile b/src/leapfrogai_ui/Makefile new file mode 100644 index 000000000..09c0a7393 --- /dev/null +++ b/src/leapfrogai_ui/Makefile @@ -0,0 +1,7 @@ +VERSION ?= $(shell git fetch --tags && git tag -l "*.*.*" | sort -V | tail -n 1 | sed -e 's/^v//') + +docker-build: + docker build -t ghcr.io/defenseunicorns/leapfrogai/leapfrogai-ui:${VERSION} . + +zarf-build: + zarf package create . --confirm --set IMAGE_VERSION=${VERSION} \ No newline at end of file diff --git a/src/leapfrogai_ui/README.md b/src/leapfrogai_ui/README.md new file mode 100644 index 000000000..e36e495ed --- /dev/null +++ b/src/leapfrogai_ui/README.md @@ -0,0 +1,193 @@ +# LeapfrogAI UI + +## Getting Started + +1. You will need Supabase installed before running the application: + [Supabase](https://supabase.com/docs/guides/cli/getting-started?platform=macos) + +2. Create a `.env` file at the route of the project, reference the `.env.example` file for values to put in the .env file + +3. Install dependencies: + +``` +npm i +npm run dev -- --open +``` + +## Building + +To create a production version of the app: + +``` +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. + +## Developer Notes + +### Tooling + +#### Husky + +This repository utilizes [Husky](https://typicode.github.io/husky/) for pre-commit checks (git hooks). + +If you need to commit and skip the git hooks: + +``` +git commit -m "..." -n # Skips Git hooks +``` + +To commit without running tests: + +``` +SKIP_TEST=true git commit -m "chore: my commit msg" +``` + +[reference the docs](https://typicode.github.io/husky/how-to.html) for other helpful tips on using husky or configuring for CI and Docker + +### Supabase + +We use Supabase for authentication and a database. Playwright tests run against a running instance of Supabase that you can start locally. You need the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) installed to do so. Before running Playwright tests, make sure Supabase and the frontend are running `npm run dev` will start both. + +Run locally: + +`npm run supabase:start` + +After it starts, the Supabase API URL and Anon key are printed to the console. These are used in the .env file to connect to Supabase. + +After starting supabase for the first time, you need to initialize the database with migrations and seed data: + +`npm run supabase:reset` + +After this initial reset, if you start Supabase again it will already have the data and you don't need to run this command unless you want to restore it to the default. + +Note - `npm run dev` will start Supabase and the frontend, but it does not run the migrations and seeding. + +Stop Supabase: + +`npm run supabase:stop` + +### Playwright End-to-End Tests + +First install Playwright: `npm init playwright@latest` + +To run the E2E tests, have the app running then: +`npm run test:integration:ui` +Click the play button in the Playwright UI. + +Note - running the script above will reset the locally running Supabase instance and re-seed the database. You will +lose existing data. + +# Supabase and Keycloak Integration + +The Supabase docs are inadequate for properly integrating with Keycloak. Additionally, they only support integration with the Supabase Cloud SAAS offering. +Before reading the section below, first reference the [Supabase docs](https://supabase.com/docs/guides/auth/social-login/auth-keycloak). + +### The following steps are required to integrate Supabase with Keycloak for local development: + +The supabase/config.toml file contains configuration options for Supabase when running it locally. When running locally, the Supabase UI dashboard does not offer +all the same configuration options that the cloud version does, so you have to specify some options in this file instead. + +The variables that had to be overridden were: + +``` +[auth] +site_url = "http://localhost:5173" +additional_redirect_urls = ["http://localhost:5173/auth/callback"] + +[auth.external.keycloak] +enabled = true +client_id = "env(SUPABASE_AUTH_KEYCLOAK_CLIENT_ID)" +secret = "env(SUPABASE_AUTH_KEYCLOAK_SECRET)" +url= "env(SUPABASE_AUTH_EXTERNAL_KEYCLOAK_URL)" + +``` + +The variables referenced in the [auth.external.keycloak] section above are in your .env file at the root of the project. +You need to create a client in Keycloak to get these variables. +Under a realm in Keycloak that is not the master realm (if using UDS, its "uds"): + +1. Create a new client (the client ID you use will be used in the env variables below) +2. Turn on "Client Authentication" +3. For "Valid redirect URLs", you need to put: + 1. `http://localhost:5173/auth/callback` (or the URL for the frontend app callback) + 2. `http://127.0.0.1:54321/auth/v1/callback` (or the URL for the Supabase callback, for locally running Supabase, DO NOT USE LOCALHOST, use 127.0.0.1) + 3. Put the same two URLs in for "Web Origins" +4. Create a user under the "Users" tab and either have them verify their email, or mark it as verified. +5. Copy the Client Secret under the Clients -> Credentials tab and use in the env variables below + +``` +#.env +SUPABASE_AUTH_KEYCLOAK_CLIENT_ID= +SUPABASE_AUTH_KEYCLOAK_SECRET= +SUPABASE_AUTH_EXTERNAL_KEYCLOAK_URL= +``` + +The `SUPABASE_AUTH_EXTERNAL_KEYCLOAK_URL` can be tricky if your Keycloak is not hosted on an actual domain. +For example, if you are running Keycloak locally, you might have it at: http://localhost:8080/auth/realms/uds +If you leave this as localhost:8080, when Supabase attempts to make a POST request to the Keycloak server during the auth process, +it will not be able to find this address and you will likely see the error "unable to exchange external code". +[This comment](https://github.com/supabase/auth/issues/516#issuecomment-1179152266) speaks to this problem, although the solutions +don't work if you are using the Supabase CLI and not running a pure [docker version of Supabase](https://supabase.com/docs/guides/self-hosting/docker). + +In order to fix this, we have to edit the /etc/hosts file in the running Supabase Auth container (we can't add this through a docker compose file +because we are using the Supabase CLI to start it up, migrate the db, and seed it). + +`npm run supabase:start` will start Supabase and modify the /etc/hosts to properly direct requests to the Keycloak server. +If you need to use a different Keycloak server for local development, you will need to modify this command. + +If your Keycloak server is not at a hosted domain, you will also need to modify the /etc/hosts on your machine: + +``` +Example: +sudo nano /etc/hosts +*add this line (edit as required)* +100.104.70.77 keycloak.admin.uds.dev +``` + +Ensure the + +``` +PUBLIC_SUPABASE_URL= +PUBLIC_SUPABASE_ANON_KEY= +``` + +variables in your .env file are pointing to the correct Supabase instance. + +Note - if connecting to a hosted Supabase instance, or in a cluster with networking, you will not need to override /etc/host files. +The: + +``` +SUPABASE_AUTH_KEYCLOAK_CLIENT_ID= +SUPABASE_AUTH_KEYCLOAK_SECRET= +SUPABASE_AUTH_EXTERNAL_KEYCLOAK_URL= +``` + +variables will also not do anything because they are only used for locally running Supabase. +You will instead need to modify the Auth provider settings directly in the Supabase dashboard and set the appropriate +redirect URLs and client ID/secret. + +If you use the component from @supabase/auth-ui-shared, you must ensure you supply provider and scope props: +ex: + +``` + +``` + +If you do not use this component and need to login with a Supabase auth command directly, ensure you provide +the "openid" scope with the options parameter. + +Login flow was adapted from [this reference](https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit?database-method=sql) diff --git a/src/leapfrogai_ui/commitlint.config.js b/src/leapfrogai_ui/commitlint.config.js new file mode 100644 index 000000000..3f5e287f9 --- /dev/null +++ b/src/leapfrogai_ui/commitlint.config.js @@ -0,0 +1 @@ +export default { extends: ['@commitlint/config-conventional'] }; diff --git a/src/leapfrogai_ui/package-lock.json b/src/leapfrogai_ui/package-lock.json new file mode 100644 index 000000000..094765d14 --- /dev/null +++ b/src/leapfrogai_ui/package-lock.json @@ -0,0 +1,8043 @@ +{ + "name": "leapfrogai-ui", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "leapfrogai-ui", + "version": "0.0.1", + "dependencies": { + "@carbon/layout": "^11.20.0", + "@carbon/themes": "^11.32.0", + "@carbon/type": "^11.26.0", + "@supabase/ssr": "^0.1.0", + "@supabase/supabase-js": "^2.39.8", + "@sveltejs/vite-plugin-svelte": "^3.0.2", + "@testing-library/user-event": "^14.5.2", + "ai": "^3.0.13", + "msw": "^2.2.3", + "openai": "^4.29.0", + "playwright": "^1.42.1", + "uuid": "^9.0.1", + "yup": "^1.4.0" + }, + "devDependencies": { + "@commitlint/cli": "^19.1.0", + "@commitlint/config-conventional": "^19.1.0", + "@faker-js/faker": "^8.4.1", + "@playwright/test": "^1.28.1", + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/adapter-node": "^5.0.1", + "@sveltejs/kit": "^2.0.0", + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/svelte": "^4.1.0", + "@types/eslint": "^8.56.0", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "carbon-components-svelte": "^0.85.0", + "carbon-icons-svelte": "^12.6.0", + "carbon-preprocess-svelte": "^0.11.0", + "dotenv": "^16.4.5", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.35.1", + "husky": "^9.0.11", + "jsdom": "^24.0.0", + "otpauth": "^9.2.2", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "sass": "^1.71.1", + "svelte": "^4.2.12", + "svelte-check": "^3.6.0", + "tslib": "^2.4.1", + "typescript": "^5.4.2", + "vite": "^5.0.3", + "vitest": "^1.2.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", + "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "peer": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bundled-es-modules/cookie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz", + "integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==", + "dependencies": { + "cookie": "^0.5.0" + } + }, + "node_modules/@bundled-es-modules/cookie/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@bundled-es-modules/statuses": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", + "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", + "dependencies": { + "statuses": "^2.0.1" + } + }, + "node_modules/@carbon/colors": { + "version": "11.21.0", + "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.21.0.tgz", + "integrity": "sha512-qvVcguNL+rOfdOv7NsJPLh6uVvRycO0e3HDl3SD5B/QhviUu76tAHpm23xwe0BDqVHGnmC71xQsUKXL5rOsMPg==", + "hasInstallScript": true, + "dependencies": { + "@ibm/telemetry-js": "^1.2.1" + } + }, + "node_modules/@carbon/grid": { + "version": "11.22.0", + "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.22.0.tgz", + "integrity": "sha512-b5R4LMRatZ0ZmRh+outCkPIFIF+gvM3sPjC0NAuAc2CQ6lAZP07/m5f8TOX9YAo10kE1j63hU+unEzs6lAHPRA==", + "hasInstallScript": true, + "dependencies": { + "@carbon/layout": "^11.21.0", + "@ibm/telemetry-js": "^1.2.1" + } + }, + "node_modules/@carbon/layout": { + "version": "11.21.0", + "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.21.0.tgz", + "integrity": "sha512-R0EEMIzdsWzF2rphzTwDJ6ywnSvDxvZwffBKn7+7bBcTWu0cp/XFeG1UzRL0LoZ25Ixv/aEQYCkoDebgUMfrfQ==", + "hasInstallScript": true, + "dependencies": { + "@ibm/telemetry-js": "^1.2.1" + } + }, + "node_modules/@carbon/themes": { + "version": "11.34.0", + "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.34.0.tgz", + "integrity": "sha512-Dxf5zgk3iuV/MmD4lu2hyScbQmesjE6fol04HPYJeAGtHud2mN+/Ti7H4W3mEcDukIosFNDXKNR39is9+lDTxA==", + "hasInstallScript": true, + "dependencies": { + "@carbon/colors": "^11.21.0", + "@carbon/layout": "^11.21.0", + "@carbon/type": "^11.26.0", + "@ibm/telemetry-js": "^1.2.1", + "color": "^4.0.0" + } + }, + "node_modules/@carbon/type": { + "version": "11.26.0", + "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.26.0.tgz", + "integrity": "sha512-Q9ehK/Q68UZjlLE4L+8AfhkNObCksCoGvPb2IMe1IkVoCjJI6QbG3yugGm4D8nfTbs3fGTGAKs4+6HkbkW8Lyw==", + "hasInstallScript": true, + "dependencies": { + "@carbon/grid": "^11.22.0", + "@carbon/layout": "^11.21.0", + "@ibm/telemetry-js": "^1.2.1" + } + }, + "node_modules/@commitlint/cli": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.1.0.tgz", + "integrity": "sha512-SYGm8HGbVzrlSYeB6oo6pG1Ec6bOMJcDsXgNGa4vgZQsPj6nJkcbTWlIRmtmIk0tHi0d5sCljGuQ+g/0NCPv7w==", + "dev": true, + "dependencies": { + "@commitlint/format": "^19.0.3", + "@commitlint/lint": "^19.1.0", + "@commitlint/load": "^19.1.0", + "@commitlint/read": "^19.0.3", + "@commitlint/types": "^19.0.3", + "execa": "^8.0.1", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.1.0.tgz", + "integrity": "sha512-KIKD2xrp6Uuk+dcZVj3++MlzIr/Su6zLE8crEDQCZNvWHNQSeeGbzOlNtsR32TUy6H3JbP7nWgduAHCaiGQ6EA==", + "dev": true, + "dependencies": { + "@commitlint/types": "^19.0.3", + "conventional-changelog-conventionalcommits": "^7.0.2" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.0.3.tgz", + "integrity": "sha512-2D3r4PKjoo59zBc2auodrSCaUnCSALCx54yveOFwwP/i2kfEAQrygwOleFWswLqK0UL/F9r07MFi5ev2ohyM4Q==", + "dev": true, + "dependencies": { + "@commitlint/types": "^19.0.3", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@commitlint/config-validator/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 + }, + "node_modules/@commitlint/ensure": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.0.3.tgz", + "integrity": "sha512-SZEpa/VvBLoT+EFZVb91YWbmaZ/9rPH3ESrINOl0HD2kMYsjvl0tF7nMHh0EpTcv4+gTtZBAe1y/SS6/OhfZzQ==", + "dev": true, + "dependencies": { + "@commitlint/types": "^19.0.3", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.0.0.tgz", + "integrity": "sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw==", + "dev": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.0.3.tgz", + "integrity": "sha512-QjjyGyoiVWzx1f5xOteKHNLFyhyweVifMgopozSgx1fGNrGV8+wp7k6n1t6StHdJ6maQJ+UUtO2TcEiBFRyR6Q==", + "dev": true, + "dependencies": { + "@commitlint/types": "^19.0.3", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.0.3.tgz", + "integrity": "sha512-MqDrxJaRSVSzCbPsV6iOKG/Lt52Y+PVwFVexqImmYYFhe51iVJjK2hRhOG2jUAGiUHk4jpdFr0cZPzcBkSzXDQ==", + "dev": true, + "dependencies": { + "@commitlint/types": "^19.0.3", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/lint": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.1.0.tgz", + "integrity": "sha512-ESjaBmL/9cxm+eePyEr6SFlBUIYlYpI80n+Ltm7IA3MAcrmiP05UMhJdAD66sO8jvo8O4xdGn/1Mt2G5VzfZKw==", + "dev": true, + "dependencies": { + "@commitlint/is-ignored": "^19.0.3", + "@commitlint/parse": "^19.0.3", + "@commitlint/rules": "^19.0.3", + "@commitlint/types": "^19.0.3" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.1.0.tgz", + "integrity": "sha512-rWqnvNDpeshX8JfUC/qjpDkQB78qF+4uHcJmIRJMwvlj6zWce08SP/TPKN3GlNKgXhAawwcAPxXL9qOTTdiOBA==", + "dev": true, + "dependencies": { + "@commitlint/config-validator": "^19.0.3", + "@commitlint/execute-rule": "^19.0.0", + "@commitlint/resolve-extends": "^19.1.0", + "@commitlint/types": "^19.0.3", + "chalk": "^5.3.0", + "cosmiconfig": "^8.3.6", + "cosmiconfig-typescript-loader": "^5.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/message": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.0.0.tgz", + "integrity": "sha512-c9czf6lU+9oF9gVVa2lmKaOARJvt4soRsVmbR7Njwp9FpbBgste5i7l/2l5o8MmbwGh4yE1snfnsy2qyA2r/Fw==", + "dev": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/parse": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.0.3.tgz", + "integrity": "sha512-Il+tNyOb8VDxN3P6XoBBwWJtKKGzHlitEuXA5BP6ir/3loWlsSqDr5aecl6hZcC/spjq4pHqNh0qPlfeWu38QA==", + "dev": true, + "dependencies": { + "@commitlint/types": "^19.0.3", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.0.3.tgz", + "integrity": "sha512-b5AflTyAXkUx5qKw4TkjjcOccXZHql3JqMi522knTQktq2AubKXFz60Sws+K4FsefwPws6fGz9mqiI/NvsvxFA==", + "dev": true, + "dependencies": { + "@commitlint/top-level": "^19.0.0", + "@commitlint/types": "^19.0.3", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.1.0.tgz", + "integrity": "sha512-z2riI+8G3CET5CPgXJPlzftH+RiWYLMYv4C9tSLdLXdr6pBNimSKukYP9MS27ejmscqCTVA4almdLh0ODD2KYg==", + "dev": true, + "dependencies": { + "@commitlint/config-validator": "^19.0.3", + "@commitlint/types": "^19.0.3", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@commitlint/rules": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.0.3.tgz", + "integrity": "sha512-TspKb9VB6svklxNCKKwxhELn7qhtY1rFF8ls58DcFd0F97XoG07xugPjjbVnLqmMkRjZDbDIwBKt9bddOfLaPw==", + "dev": true, + "dependencies": { + "@commitlint/ensure": "^19.0.3", + "@commitlint/message": "^19.0.0", + "@commitlint/to-lines": "^19.0.0", + "@commitlint/types": "^19.0.3", + "execa": "^8.0.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.0.0.tgz", + "integrity": "sha512-vkxWo+VQU5wFhiP9Ub9Sre0FYe019JxFikrALVoD5UGa8/t3yOJEpEhxC5xKiENKKhUkTpEItMTRAjHw2SCpZw==", + "dev": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.0.0.tgz", + "integrity": "sha512-KKjShd6u1aMGNkCkaX4aG1jOGdn7f8ZI8TR1VEuNqUOjWTOdcDSsmglinglJ18JTjuBX5I1PtjrhQCRcixRVFQ==", + "dev": true, + "dependencies": { + "find-up": "^7.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level/node_modules/find-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "dev": true, + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@commitlint/top-level/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/types": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.0.3.tgz", + "integrity": "sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==", + "dev": true, + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@faker-js/faker": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz", + "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0", + "npm": ">=6.14.13" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@ibm/telemetry-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ibm/telemetry-js/-/telemetry-js-1.3.0.tgz", + "integrity": "sha512-9gIkyF2B9RizWN6rsdQN76DN6D+/Xbr4HGTwm6EUujfXvEVtWbf4jzxDFwKvZkeTC2tjHpkUNJQKdivbMKt8yg==", + "bin": { + "ibmtelemetry": "dist/collect.js" + } + }, + "node_modules/@inquirer/confirm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.0.tgz", + "integrity": "sha512-nH5mxoTEoqk6WpoBz80GMpDSm9jH5V9AF8n+JZAZfMzd9gHeEG9w1o3KawPRR72lfzpP+QxBHLkOKLEApwhDiQ==", + "dependencies": { + "@inquirer/core": "^7.1.0", + "@inquirer/type": "^1.2.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-7.1.0.tgz", + "integrity": "sha512-FRCiDiU54XHt5B/D8hX4twwZuzSP244ANHbu3R7CAsJfiv1dUOz24ePBgCZjygEjDUi6BWIJuk4eWLKJ7LATUw==", + "dependencies": { + "@inquirer/type": "^1.2.1", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.11.26", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=18" + } + }, + "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==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.2.1.tgz", + "integrity": "sha512-xwMfkPAxeo8Ji/IxfUSqzRi0/+F2GIqJmpc5/thelgMGsjNZcjDDRBO9TLXT1s/hdx/mK5QbVIvgoLIFgXhTMQ==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mswjs/cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-1.1.0.tgz", + "integrity": "sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.25.16", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.25.16.tgz", + "integrity": "sha512-8QC8JyKztvoGAdPgyZy49c9vSHHAZjHagwl4RY9E8carULk8ym3iTaiawrT1YoLF/qb449h48f71XDPgkUSOUg==", + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, + "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, + "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, + "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, + "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", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==" + }, + "node_modules/@playwright/test": { + "version": "1.42.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz", + "integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==", + "dev": true, + "dependencies": { + "playwright": "1.42.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.24", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz", + "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==", + "dev": true + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "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 + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "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 + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.1.tgz", + "integrity": "sha512-iU2Sya8hNn1LhsYyf0N+L4Gf9Qc+9eBTJJJsaOGUp+7x4n2M9dxTt8UvhJl3oeftSjblSlpCfvjA/IfP3g5VjQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.1.tgz", + "integrity": "sha512-wlzcWiH2Ir7rdMELxFE5vuM7D6TsOcJ2Yw0c3vaBR3VOsJFVTx9xvwnAvhgU5Ii8Gd6+I11qNHwndDscIm0HXg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.1.tgz", + "integrity": "sha512-YRXa1+aZIFN5BaImK+84B3uNK8C6+ynKLPgvn29X9s0LTVCByp54TB7tdSMHDR7GTV39bz1lOmlLDuedgTwwHg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.1.tgz", + "integrity": "sha512-opjWJ4MevxeA8FhlngQWPBOvVWYNPFkq6/25rGgG+KOy0r8clYwL1CFd+PGwRqqMFVQ4/Qd3sQu5t7ucP7C/Uw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.1.tgz", + "integrity": "sha512-uBkwaI+gBUlIe+EfbNnY5xNyXuhZbDSx2nzzW8tRMjUmpScd6lCQYKY2V9BATHtv5Ef2OBq6SChEP8h+/cxifQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.1.tgz", + "integrity": "sha512-0bK9aG1kIg0Su7OcFTlexkVeNZ5IzEsnz1ept87a0TUgZ6HplSgkJAnFpEVRW7GRcikT4GlPV0pbtVedOaXHQQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.1.tgz", + "integrity": "sha512-qB6AFRXuP8bdkBI4D7UPUbE7OQf7u5OL+R94JE42Z2Qjmyj74FtDdLGeriRyBDhm4rQSvqAGCGC01b8Fu2LthQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.1.tgz", + "integrity": "sha512-sHig3LaGlpNgDj5o8uPEoGs98RII8HpNIqFtAI8/pYABO8i0nb1QzT0JDoXF/pxzqO+FkxvwkHZo9k0NJYDedg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.1.tgz", + "integrity": "sha512-nD3YcUv6jBJbBNFvSbp0IV66+ba/1teuBcu+fBBPZ33sidxitc6ErhON3JNavaH8HlswhWMC3s5rgZpM4MtPqQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.1.tgz", + "integrity": "sha512-7/XVZqgBby2qp/cO0TQ8uJK+9xnSdJ9ct6gSDdEr4MfABrjTyrW6Bau7HQ73a2a5tPB7hno49A0y1jhWGDN9OQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.1.tgz", + "integrity": "sha512-CYc64bnICG42UPL7TrhIwsJW4QcKkIt9gGlj21gq3VV0LL6XNb1yAdHVp1pIi9gkts9gGcT3OfUYHjGP7ETAiw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.1.tgz", + "integrity": "sha512-LN+vnlZ9g0qlHGlS920GR4zFCqAwbv2lULrR29yGaWP9u7wF5L7GqWu9Ah6/kFZPXPUkpdZwd//TNR+9XC9hvA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.1.tgz", + "integrity": "sha512-n+vkrSyphvmU0qkQ6QBNXCGr2mKjhP08mPRM/Xp5Ck2FV4NrHU+y6axzDeixUrCBHVUS51TZhjqrKBBsHLKb2Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@supabase/functions-js": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.1.5.tgz", + "integrity": "sha512-BNzC5XhCzzCaggJ8s53DP+WeHHGT/NfTsx2wUSSGKR2/ikLFQTBCDzMvGz/PxYMqRko/LwncQtKXGOYp1PkPaw==", + "dependencies": { + "@supabase/node-fetch": "^2.6.14" + } + }, + "node_modules/@supabase/gotrue-js": { + "version": "2.62.2", + "resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-2.62.2.tgz", + "integrity": "sha512-AP6e6W9rQXFTEJ7sTTNYQrNf0LCcnt1hUW+RIgUK+Uh3jbWvcIST7wAlYyNZiMlS9+PYyymWQ+Ykz/rOYSO0+A==", + "dependencies": { + "@supabase/node-fetch": "^2.6.14" + } + }, + "node_modules/@supabase/node-fetch": { + "version": "2.6.15", + "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz", + "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/@supabase/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/@supabase/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/@supabase/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/@supabase/postgrest-js": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.9.2.tgz", + "integrity": "sha512-I6yHo8CC9cxhOo6DouDMy9uOfW7hjdsnCxZiaJuIVZm1dBGTFiQPgfMa9zXCamEWzNyWRjZvupAUuX+tqcl5Sw==", + "dependencies": { + "@supabase/node-fetch": "^2.6.14" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.9.3.tgz", + "integrity": "sha512-lAp50s2n3FhGJFq+wTSXLNIDPw5Y0Wxrgt44eM5nLSA3jZNUUP3Oq2Ccd1CbZdVntPCWLZvJaU//pAd2NE+QnQ==", + "dependencies": { + "@supabase/node-fetch": "^2.6.14", + "@types/phoenix": "^1.5.4", + "@types/ws": "^8.5.10", + "ws": "^8.14.2" + } + }, + "node_modules/@supabase/ssr": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@supabase/ssr/-/ssr-0.1.0.tgz", + "integrity": "sha512-bIVrkqjAK5G3KjkIMKYKtAOlCgRRplEWjrlyRyXSOYtgDieiOhk2ZyNAPsEOa1By9OZVxuX5eAW1fitdnuxayw==", + "dependencies": { + "cookie": "^0.5.0", + "ramda": "^0.29.0" + }, + "peerDependencies": { + "@supabase/supabase-js": "^2.33.1" + } + }, + "node_modules/@supabase/ssr/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.5.tgz", + "integrity": "sha512-OpLoDRjFwClwc2cjTJZG8XviTiQH4Ik8sCiMK5v7et0MDu2QlXjCAW3ljxJB5+z/KazdMOTnySi+hysxWUPu3w==", + "dependencies": { + "@supabase/node-fetch": "^2.6.14" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.39.8", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.39.8.tgz", + "integrity": "sha512-WpiawHjseIRcCQTZbMJtHUSOepz5+M9qE1jP9BDmg8X7ehALFwgEkiKyHAu59qm/pKP2ryyQXLtu2XZNRbUarw==", + "dependencies": { + "@supabase/functions-js": "2.1.5", + "@supabase/gotrue-js": "2.62.2", + "@supabase/node-fetch": "2.6.15", + "@supabase/postgrest-js": "1.9.2", + "@supabase/realtime-js": "2.9.3", + "@supabase/storage-js": "2.5.5" + } + }, + "node_modules/@sveltejs/adapter-auto": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.1.1.tgz", + "integrity": "sha512-6LeZft2Fo/4HfmLBi5CucMYmgRxgcETweQl/yQoZo/895K3S9YWYN4Sfm/IhwlIpbJp3QNvhKmwCHbsqQNYQpw==", + "dev": true, + "dependencies": { + "import-meta-resolve": "^4.0.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/adapter-node": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.0.1.tgz", + "integrity": "sha512-eYdmxdUWMW+dad1JfMsWBPY2vjXz9eE+52A2AQnXPScPJlIxIVk5mmbaEEzrZivLfO2wEcLTZ5vdC03W69x+iA==", + "dev": true, + "dependencies": { + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "rollup": "^4.9.5" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.4.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.2.tgz", + "integrity": "sha512-1Pm2lsBYURQsjnLyZa+jw75eVD4gYHxGRwPyFe4DAmB3FjTVR8vRNWGeuDLGFcKMh/B1ij6FTUrc9GrerogCng==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0", + "devalue": "^4.3.2", + "esm-env": "^1.0.0", + "import-meta-resolve": "^4.0.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^2.0.4", + "tiny-glob": "^0.2.9" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.3" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.2.tgz", + "integrity": "sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "svelte-hmr": "^0.15.3", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz", + "integrity": "sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@testing-library/dom": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", + "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz", + "integrity": "sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.3.2", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/bun": "latest", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/bun": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true + }, + "node_modules/@testing-library/svelte": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/svelte/-/svelte-4.1.0.tgz", + "integrity": "sha512-MJqe7x9WowkiAVdk9mvazEC2ktFZdmK2OqFVoO557PC37aBemQ4ozqdK3yrG34Zg9kuln3qgTVeLSh08e69AMw==", + "dev": true, + "dependencies": { + "@testing-library/dom": "^9.3.1" + }, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "svelte": "^3 || ^4" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==" + }, + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" + }, + "node_modules/@types/diff-match-patch": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", + "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==" + }, + "node_modules/@types/eslint": { + "version": "8.56.5", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz", + "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.11.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.26.tgz", + "integrity": "sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/phoenix": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.4.tgz", + "integrity": "sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA==" + }, + "node_modules/@types/pug": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", + "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", + "dev": true + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/statuses": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz", + "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==" + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true + }, + "node_modules/@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==" + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz", + "integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/type-utils": "7.1.1", + "@typescript-eslint/utils": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", + "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", + "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", + "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", + "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz", + "integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz", + "integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/utils": "7.1.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.1.tgz", + "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz", + "integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.1.tgz", + "integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz", + "integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitest/expect": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", + "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==", + "dev": true, + "dependencies": { + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz", + "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==", + "dev": true, + "dependencies": { + "@vitest/utils": "1.3.1", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz", + "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", + "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==", + "dev": true, + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz", + "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", + "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", + "peer": true, + "dependencies": { + "@babel/parser": "^7.23.9", + "@vue/shared": "3.4.21", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-core/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==", + "peer": true + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", + "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", + "peer": true, + "dependencies": { + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", + "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", + "peer": true, + "dependencies": { + "@babel/parser": "^7.23.9", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.7", + "postcss": "^8.4.35", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-sfc/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==", + "peer": true + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", + "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", + "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", + "peer": true, + "dependencies": { + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", + "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", + "peer": true, + "dependencies": { + "@vue/reactivity": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", + "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", + "peer": true, + "dependencies": { + "@vue/runtime-core": "3.4.21", + "@vue/shared": "3.4.21", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", + "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", + "peer": true, + "dependencies": { + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "vue": "3.4.21" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", + "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==", + "peer": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ai": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/ai/-/ai-3.0.13.tgz", + "integrity": "sha512-fDrYnVTdMJuS/qYUq0T/CX3WDuTfcZFie9LkgnoQ2layfUG2Wzh/mpfkfYXFEq/mqnpep3xUtECOB1weyyvwUg==", + "dependencies": { + "eventsource-parser": "1.0.0", + "jsondiffpatch": "^0.6.0", + "nanoid": "3.3.6", + "solid-swr-store": "0.10.7", + "sswr": "2.0.0", + "swr": "2.2.0", + "swr-store": "0.10.6", + "swrv": "1.0.4", + "zod-to-json-schema": "^3.22.4" + }, + "engines": { + "node": ">=14.6" + }, + "peerDependencies": { + "react": "^18.2.0", + "solid-js": "^1.7.7", + "svelte": "^3.0.0 || ^4.0.0", + "vue": "^3.3.4", + "zod": "^3.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "solid-js": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/ai/node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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, + "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/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "devOptional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "devOptional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/carbon-components-svelte": { + "version": "0.85.0", + "resolved": "https://registry.npmjs.org/carbon-components-svelte/-/carbon-components-svelte-0.85.0.tgz", + "integrity": "sha512-inJs4RE7ubiOafuiDkUkiV/np8ab63nzDNp+x2k+7kUhewtrYNTTyMHsMM/y2eQS042riXLzAxNsqF7MXm+kfA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@ibm/telemetry-js": "^1.2.1", + "flatpickr": "4.6.9" + } + }, + "node_modules/carbon-icons-svelte": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/carbon-icons-svelte/-/carbon-icons-svelte-12.6.0.tgz", + "integrity": "sha512-tw5jUSASVfdZ30CcynKWwQalkUIn3I2OFKvyormaoNH6bWjtXp21ESqDSuZ0RgZbxzaeBoUJaEJpsSTX5YjElA==", + "dev": true + }, + "node_modules/carbon-preprocess-svelte": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/carbon-preprocess-svelte/-/carbon-preprocess-svelte-0.11.0.tgz", + "integrity": "sha512-J0Y7yhUmtMWX+c9iLeoqFFY+Yz/neBka3JQNPMlJ1ucAqBkrCl+/9bJAHYYglK8YTfvxrMPdkSZPqyjEplF3Ww==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.8", + "postcss": "^8.4.36", + "postcss-discard-empty": "^6.0.3" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "devOptional": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "devOptional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "engines": { + "node": ">= 12" + } + }, + "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==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "dependencies": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", + "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", + "dev": true, + "dependencies": { + "jiti": "^1.19.1" + }, + "engines": { + "node": ">=v16" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=8.2", + "typescript": ">=4" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "engines": { + "node": "*" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "peer": true + }, + "node_modules/dargs": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", + "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz", + "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==", + "dev": true + }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/digest-fetch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", + "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", + "dependencies": { + "base-64": "^0.1.0", + "md5": "^2.3.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "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==" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz", + "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-svelte": { + "version": "2.35.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.35.1.tgz", + "integrity": "sha512-IF8TpLnROSGy98Z3NrsKXWDSCbNY2ReHDcrYTuXZMbfX7VmESISR78TWgO9zdg4Dht1X8coub5jKwHzP0ExRug==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@jridgewell/sourcemap-codec": "^1.4.14", + "debug": "^4.3.1", + "eslint-compat-utils": "^0.1.2", + "esutils": "^2.0.3", + "known-css-properties": "^0.29.0", + "postcss": "^8.4.5", + "postcss-load-config": "^3.1.4", + "postcss-safe-parser": "^6.0.0", + "postcss-selector-parser": "^6.0.11", + "semver": "^7.5.3", + "svelte-eslint-parser": ">=0.33.0 <1.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0-0", + "svelte": "^3.37.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventsource-parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.0.0.tgz", + "integrity": "sha512-9jgfSCa3dmEme2ES3mPByGXfgZ87VbP97tng1G2nWwWx6bV2nYxm2AWCrbQjXToSe+yYlqaZNtxffR9IeQr95g==", + "engines": { + "node": ">=14.18" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "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.4" + }, + "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, + "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", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "devOptional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatpickr": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.9.tgz", + "integrity": "sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw==", + "dev": true + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/formdata-node/node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", + "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "dev": true, + "dependencies": { + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": 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 + }, + "node_modules/graphql": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/headers-polyfill": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.2.tgz", + "integrity": "sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw==" + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/husky": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", + "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", + "dev": true, + "bin": { + "husky": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "devOptional": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", + "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "devOptional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "devOptional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", + "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.0.0.tgz", + "integrity": "sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==", + "dev": true, + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.7", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.16.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "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 + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, + "node_modules/jsondiffpatch": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz", + "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==", + "dependencies": { + "@types/diff-match-patch": "^1.0.36", + "chalk": "^5.3.0", + "diff-match-patch": "^1.0.5" + }, + "bin": { + "jsondiffpatch": "bin/jsondiffpatch.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/jsondiffpatch/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jssha": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jssha/-/jssha-3.3.1.tgz", + "integrity": "sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/known-css-properties": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", + "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==", + "dev": true + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loose-envify/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "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, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mlly": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", + "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.0.3", + "ufo": "^1.3.2" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/msw": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.2.3.tgz", + "integrity": "sha512-84CoNCkcJ/EvY8Tv0tD/6HKVd4S5HyGowHjM5W12K8Wgryp4fikqS7IaTOceyQgP5dNedxo2icTLDXo7dkpxCg==", + "hasInstallScript": true, + "dependencies": { + "@bundled-es-modules/cookie": "^2.0.0", + "@bundled-es-modules/statuses": "^1.0.1", + "@inquirer/confirm": "^3.0.0", + "@mswjs/cookies": "^1.1.0", + "@mswjs/interceptors": "^0.25.16", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.6.0", + "@types/statuses": "^2.0.4", + "chalk": "^4.1.2", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.2", + "path-to-regexp": "^6.2.0", + "strict-event-emitter": "^0.5.1", + "type-fest": "^4.9.0", + "yargs": "^17.7.2" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.7.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/msw/node_modules/type-fest": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.12.0.tgz", + "integrity": "sha512-5Y2/pp2wtJk8o08G0CMkuFPCO354FGwk/vbidxrdhRGZfd0tFnb4Qb8anp9XxXriwBgVPjdWbKpGl4J9lJY2jQ==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.29.0.tgz", + "integrity": "sha512-ic6C681bSow1XQdKhADthM/OOKqNL05M1gCFLx1mRqLJ+yH49v6qnvaWQ76kwqI/IieCuVTXfRfTk3sz4cB45w==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "digest-fetch": "^1.3.0", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "web-streams-polyfill": "^3.2.1" + }, + "bin": { + "openai": "bin/cli" + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.24.tgz", + "integrity": "sha512-eghAz3gnbQbvnHqB+mgB2ZR3aH6RhdEmHGS48BnV75KceQPHqabkxKI0BbUSsqhqy2Ddhc2xD/VAR9ySZd57Lw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/otpauth": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/otpauth/-/otpauth-9.2.2.tgz", + "integrity": "sha512-2VcnYRUmq1dNckIfySNYP32ITWp1bvTeAEW0BSCR6G3GBf3a5zb9E+ubY62t3Dma9RjoHlvd7QpmzHfJZRkiNg==", + "dev": true, + "dependencies": { + "jssha": "~3.3.1" + }, + "funding": { + "url": "https://github.com/hectorm/otpauth?sponsor=1" + } + }, + "node_modules/outvariant": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.2.tgz", + "integrity": "sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==" + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", + "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.2.0", + "pathe": "^1.1.0" + } + }, + "node_modules/playwright": { + "version": "1.42.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz", + "integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==", + "dependencies": { + "playwright-core": "1.42.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.42.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz", + "integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-safe-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "dev": true, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-svelte": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.2.tgz", + "integrity": "sha512-ZzzE/wMuf48/1+Lf2Ffko0uDa6pyCfgHV6+uAhtg2U0AAXGrhCSW88vEJNAkAxW5qyrFY1y1zZ4J8TgHrjW++Q==", + "dev": true, + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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" + } + ] + }, + "node_modules/ramda": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", + "integrity": "sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "devOptional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.1.tgz", + "integrity": "sha512-ggqQKvx/PsB0FaWXhIvVkSWh7a/PCLQAsMjBc+nA2M8Rv2/HG0X6zvixAB7KyZBRtifBUhy5k8voQX/mRnABPg==", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.12.1", + "@rollup/rollup-android-arm64": "4.12.1", + "@rollup/rollup-darwin-arm64": "4.12.1", + "@rollup/rollup-darwin-x64": "4.12.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.1", + "@rollup/rollup-linux-arm64-gnu": "4.12.1", + "@rollup/rollup-linux-arm64-musl": "4.12.1", + "@rollup/rollup-linux-riscv64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-musl": "4.12.1", + "@rollup/rollup-win32-arm64-msvc": "4.12.1", + "@rollup/rollup-win32-ia32-msvc": "4.12.1", + "@rollup/rollup-win32-x64-msvc": "4.12.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "engines": { + "node": ">=0.12.0" + } + }, + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sander": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", + "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", + "dev": true, + "dependencies": { + "es6-promise": "^3.1.2", + "graceful-fs": "^4.1.3", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2" + } + }, + "node_modules/sander/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/sass": { + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "devOptional": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/seroval": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.0.5.tgz", + "integrity": "sha512-TM+Z11tHHvQVQKeNlOUonOWnsNM+2IBwZ4vwoi4j3zKzIpc5IDw8WPwCfcc8F17wy6cBcJGbZbFOR0UCuTZHQA==", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/seroval-plugins": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.0.5.tgz", + "integrity": "sha512-8+pDC1vOedPXjKG7oz8o+iiHrtF2WswaMQJ7CKFpccvSYfrzmvKY9zOJWCg+881722wIHfwkdnRmiiDm9ym+zQ==", + "peer": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/solid-js": { + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.16.tgz", + "integrity": "sha512-rja94MNU9flF3qQRLNsu60QHKBDKBkVE1DldJZPIfn2ypIn3NV2WpSbGTQIvsyGPBo+9E2IMjwqnqpbgfWuzeg==", + "peer": true, + "dependencies": { + "csstype": "^3.1.0", + "seroval": "^1.0.4", + "seroval-plugins": "^1.0.3" + } + }, + "node_modules/solid-swr-store": { + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/solid-swr-store/-/solid-swr-store-0.10.7.tgz", + "integrity": "sha512-A6d68aJmRP471aWqKKPE2tpgOiR5fH4qXQNfKIec+Vap+MGQm3tvXlT8n0I8UgJSlNAsSAUuw2VTviH2h3Vv5g==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "solid-js": "^1.2", + "swr-store": "^0.10" + } + }, + "node_modules/sorcery": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", + "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.14", + "buffer-crc32": "^0.2.5", + "minimist": "^1.2.0", + "sander": "^0.5.0" + }, + "bin": { + "sorcery": "bin/sorcery" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sswr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sswr/-/sswr-2.0.0.tgz", + "integrity": "sha512-mV0kkeBHcjcb0M5NqKtKVg/uTIYNlIIniyDfSGrSfxpEdM9C365jK0z55pl9K0xAkNTJi2OAOVFQpgMPUk+V0w==", + "dependencies": { + "swrev": "^4.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "dev": true + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==" + }, + "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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", + "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", + "dev": true, + "dependencies": { + "js-tokens": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.12.tgz", + "integrity": "sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug==", + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/svelte-check": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.6.tgz", + "integrity": "sha512-b9q9rOHOMYF3U8XllK7LmXTq1LeWQ98waGfEJzrFutViadkNl1tgdEtxIQ8yuPx+VQ4l7YrknYol+0lfZocaZw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "chokidar": "^3.4.1", + "fast-glob": "^3.2.7", + "import-fresh": "^3.2.1", + "picocolors": "^1.0.0", + "sade": "^1.7.4", + "svelte-preprocess": "^5.1.3", + "typescript": "^5.0.3" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "peerDependencies": { + "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" + } + }, + "node_modules/svelte-eslint-parser": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz", + "integrity": "sha512-vo7xPGTlKBGdLH8T5L64FipvTrqv3OQRx9d2z5X05KKZDlF4rQk8KViZO4flKERY+5BiVdOh7zZ7JGJWo5P0uA==", + "dev": true, + "dependencies": { + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "postcss": "^8.4.29", + "postcss-scss": "^4.0.8" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "svelte": "^3.37.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/svelte-hmr": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", + "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, + "node_modules/svelte-preprocess": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz", + "integrity": "sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/pug": "^2.0.6", + "detect-indent": "^6.1.0", + "magic-string": "^0.30.5", + "sorcery": "^0.11.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">= 16.0.0", + "pnpm": "^8.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.2", + "coffeescript": "^2.5.1", + "less": "^3.11.3 || ^4.0.0", + "postcss": "^7 || ^8", + "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "pug": "^3.0.0", + "sass": "^1.26.8", + "stylus": "^0.55.0", + "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", + "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "coffeescript": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "postcss-load-config": { + "optional": true + }, + "pug": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/swr": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.0.tgz", + "integrity": "sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==", + "dependencies": { + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/swr-store": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/swr-store/-/swr-store-0.10.6.tgz", + "integrity": "sha512-xPjB1hARSiRaNNlUQvWSVrG5SirCjk2TmaUyzzvk69SZQan9hCJqw/5rG9iL7xElHU784GxRPISClq4488/XVw==", + "dependencies": { + "dequal": "^2.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swrev": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/swrev/-/swrev-4.0.0.tgz", + "integrity": "sha512-LqVcOHSB4cPGgitD1riJ1Hh4vdmITOp+BkmfmXRh4hSF/t7EnS4iD+SOTmq7w5pPm/SiPeto4ADbKS6dHUDWFA==" + }, + "node_modules/swrv": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/swrv/-/swrv-1.0.4.tgz", + "integrity": "sha512-zjEkcP8Ywmj+xOJW3lIT65ciY/4AL4e/Or7Gj0MzU3zBJNMdJiT8geVZhINavnlHRMMCcJLHhraLTAiDOTmQ9g==", + "peerDependencies": { + "vue": ">=3.2.26 < 4" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" + }, + "node_modules/tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "dependencies": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "node_modules/tinybench": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", + "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.2.tgz", + "integrity": "sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "devOptional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-api-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz", + "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", + "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz", + "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "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==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", + "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==", + "dev": true, + "dependencies": { + "@vitest/expect": "1.3.1", + "@vitest/runner": "1.3.1", + "@vitest/snapshot": "1.3.1", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.2", + "vite": "^5.0.0", + "vite-node": "1.3.1", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.3.1", + "@vitest/ui": "1.3.1", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", + "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/runtime-dom": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "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/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==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yup": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", + "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", + "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "peerDependencies": { + "zod": "^3.22.4" + } + } + } +} diff --git a/src/leapfrogai_ui/package.json b/src/leapfrogai_ui/package.json new file mode 100644 index 000000000..cf2bc1e50 --- /dev/null +++ b/src/leapfrogai_ui/package.json @@ -0,0 +1,74 @@ +{ + "name": "leapfrogai-ui", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "npm run supabase:start && vite dev", + "build": "vite build", + "preview": "vite preview", + "test": "npm run test:integration && npm run test:unit", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --check . && eslint .", + "format": "prettier --write .", + "test:integration": "supabase db reset && playwright test", + "test:integration:ui": "supabase db reset && playwright test --ui", + "test:unit": "vitest run", + "test:unit:watch": "vitest", + "prepare": "husky", + "supabase:start": "supabase start && docker exec -u 0 supabase_auth_supabase /bin/sh -c \"echo '100.104.70.77 keycloak.admin.uds.dev' >> /etc/hosts\"", + "supabase:stop": "supabase stop", + "supabase:reset": "supabase db reset", + "supbase:migrate": "supbase migration up" + }, + "devDependencies": { + "@commitlint/cli": "^19.1.0", + "@commitlint/config-conventional": "^19.1.0", + "@faker-js/faker": "^8.4.1", + "@playwright/test": "^1.28.1", + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/adapter-node": "^5.0.1", + "@sveltejs/kit": "^2.0.0", + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/svelte": "^4.1.0", + "@types/eslint": "^8.56.0", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "carbon-components-svelte": "^0.85.0", + "carbon-icons-svelte": "^12.6.0", + "carbon-preprocess-svelte": "^0.11.0", + "dotenv": "^16.4.5", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.35.1", + "husky": "^9.0.11", + "jsdom": "^24.0.0", + "otpauth": "^9.2.2", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "sass": "^1.71.1", + "svelte": "^4.2.12", + "svelte-check": "^3.6.0", + "tslib": "^2.4.1", + "typescript": "^5.4.2", + "vite": "^5.0.3", + "vitest": "^1.2.0" + }, + "type": "module", + "dependencies": { + "@carbon/layout": "^11.20.0", + "@carbon/themes": "^11.32.0", + "@carbon/type": "^11.26.0", + "@supabase/ssr": "^0.1.0", + "@supabase/supabase-js": "^2.39.8", + "@sveltejs/vite-plugin-svelte": "^3.0.2", + "@testing-library/user-event": "^14.5.2", + "ai": "^3.0.13", + "msw": "^2.2.3", + "openai": "^4.29.0", + "playwright": "^1.42.1", + "uuid": "^9.0.1", + "yup": "^1.4.0" + } +} diff --git a/src/leapfrogai_ui/playwright.config.ts b/src/leapfrogai_ui/playwright.config.ts new file mode 100644 index 000000000..934add0a5 --- /dev/null +++ b/src/leapfrogai_ui/playwright.config.ts @@ -0,0 +1,51 @@ +import { devices } from '@playwright/test'; +import type { PlaywrightTestConfig } from '@playwright/test'; +import dotenv from 'dotenv'; + +dotenv.config(); + +const config: PlaywrightTestConfig = { + projects: [ + { name: 'setup', testMatch: /.*\.setup\.ts/ }, + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + // Use prepared auth state. + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] + }, + { + name: 'firefox', + use: { + ...devices['Desktop Firefox'], + // Use prepared auth state. + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] + }, + { + name: 'webkit', + use: { ...devices['Desktop Safari'], storageState: 'playwright/.auth/user.json' }, + dependencies: ['setup'] + }, + { + name: 'Edge', + use: { + ...devices['Desktop Edge'], + channel: 'msedge', + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] + } + ], + webServer: { + command: 'npm run build && npm run preview', + port: 4173 + }, + testDir: 'tests', + testMatch: /(.+\.)?(test|spec)\.[jt]s/ +}; + +export default config; diff --git a/src/leapfrogai_ui/src/app.d.ts b/src/leapfrogai_ui/src/app.d.ts new file mode 100644 index 000000000..4fa94ff34 --- /dev/null +++ b/src/leapfrogai_ui/src/app.d.ts @@ -0,0 +1,24 @@ +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +import { SupabaseClient, Session } from '@supabase/supabase-js'; + +declare global { + namespace App { + // interface Error {} + interface Locals { + supabase: SupabaseClient; + getSession(): Promise; + } + interface PageData { + title?: string | null; + session: Session | null; + // TODO - add profile type + // profile?: any; + conversations?: Conversation[]; + } + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/src/leapfrogai_ui/src/app.html b/src/leapfrogai_ui/src/app.html new file mode 100644 index 000000000..77a5ff52c --- /dev/null +++ b/src/leapfrogai_ui/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/leapfrogai_ui/src/hooks.server.ts b/src/leapfrogai_ui/src/hooks.server.ts new file mode 100644 index 000000000..ba1d65cbd --- /dev/null +++ b/src/leapfrogai_ui/src/hooks.server.ts @@ -0,0 +1,46 @@ +import { env } from '$env/dynamic/public'; +import { createServerClient } from '@supabase/ssr'; +import type { Handle } from '@sveltejs/kit'; + +export const handle: Handle = async ({ event, resolve }) => { + event.locals.supabase = createServerClient( + env.PUBLIC_SUPABASE_URL, + env.PUBLIC_SUPABASE_ANON_KEY, + { + cookies: { + get: (key) => event.cookies.get(key), + /** + * Note: You have to add the `path` variable to the + * set and remove method due to sveltekit's cookie API + * requiring this to be set, setting the path to `/` + * will replicate previous/standard behaviour (https://kit.svelte.dev/docs/types#public-types-cookies) + */ + set: (key, value, options) => { + event.cookies.set(key, value, { ...options, path: '/' }); + }, + remove: (key, options) => { + event.cookies.delete(key, { ...options, path: '/' }); + } + } + } + ); + + /** + * A convenience helper so we can just call await getSession() instead const { data: { session } } = await supabase.auth.getSession() + */ + event.locals.getSession = async () => { + const { + data: { session } + } = await event.locals.supabase.auth.getSession(); + return session; + }; + + return resolve(event, { + filterSerializedResponseHeaders(name) { + return name === 'content-range'; + } + }); +}; + +// Note that auth.getSession reads the auth token and the unencoded session data from the local storage medium. It doesn't send a request back to the Supabase Auth server unless the local session is expired. +// You should never trust the unencoded session data if you're writing server code, since it could be tampered with by the sender. If you need verified, trustworthy user data, call auth.getUser instead, which always makes a request to the Auth server to fetch trusted data. diff --git a/src/leapfrogai_ui/src/lib/assets/DefenseUnicorns.png b/src/leapfrogai_ui/src/lib/assets/DefenseUnicorns.png new file mode 100644 index 0000000000000000000000000000000000000000..cac516fb28e38a6dfb516cc61d0b92ee5205a743 GIT binary patch literal 15824 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 JPDHLkV1m=6GP3{x literal 0 HcmV?d00001 diff --git a/src/leapfrogai_ui/src/lib/assets/LeapfrogAI.png b/src/leapfrogai_ui/src/lib/assets/LeapfrogAI.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb2e71d4ae9a7be44b288b712ad22d0f1b82ad7 GIT binary patch literal 127778 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 z

C6a%SiJv!s6aH$EF$g2equOR>x88x{vg|E^fuIh4Oa5%1BRM7+A$Ni{b_ozif7U$FQK6 zv;ljJw_W#bmv1|-j!AG&l?5{tZbiQ4k~}oV=cvShNCDw>DNhBw(5~`iXHA9GkK@a} znR>NDs^U+`wOq(L4;4vt2li}9c|^&`5pKL;?GO)+$b+#nQ??NDB3gNu?+z{L_XK+# z5!VPCulpBU^Z|SredQ^AMZD-;ezt^;MBiu=S^9H*=EJ^%JD7t#E=-6;1ps03{ zKrB!)r2;FDkO6|Hp%f&2sFxY#^4$uIRW};PYeeohKL{jjJ^Itbdw4|B7FOowY=YzA zv)Snz?KkreSB?8yC%& z;!Kz7+J7!;zWXT~RzLDBKVK0F4m?h{#Qe&fUu^!hURTGcVch#X84AP30qFEnPwZ}) z)g`cB#E(^?;!+p1;I?MC6Xp#mEFVvGz_w9M-drf1&F&Nq1uI!v`hRP0At*`zZOO*{Q$~uZJnB!5!yFfkyJ2F-BRIpPX zvk_nYiS`982ZKuKwDFi;u-8%7ux7GR)P1+?#^MV~Ca!hVkyMbf=r^bR^q`zKPZ7dA zr)>p8`qz*l?!H30!~2-xX+;EV%%4@v?gQ0)i~_Okz(2f;5&<^Z%;b_M)5qKye1C{) zNHLTEJ|vJqZl(~P;JxD_xS6Ey&d+dihR>z;+;8r6bjBj1D-xPFf&0UM_Q$c%t%A^j zk=LRnuT9lQoLC>~@u!mf;13yCwbQ(`loyyLtPXY=!Ec@tYP!G~%;`A23BqW(Qv9qp~=CkeC zH%v(8`11Vka3$M;AFeMOvR>z9Uqk1*p$f83zZ}X`evBBnyjZU;TNAIw+E4K{`wJX2 zfQRIs!hrwnm0yn|E__Eu1QsGOm@I^o5`UZj3^UGR^Nj>{jJV@rVP&s$umkA{`tk*g zC2r025JjB^GA|Uu5KdlwZrsE8AEkLBU8+qJ9P&ThvhDiQjKLL&mq7d7`sk5-(wAyL ztPN4StNlhVkhl56M0Gg+jLO(?CVveQ#aJqCpH- zqX%nFUTCogOS84#f{MP{l;>?iDuW`3GAqqLYfhl|Y#gwSXsGzX_k6L5^{DIo{pR(8 z7Q@!M=!N#A}c)+>8+6=d?liJZ4LB)SoSy!}XdV@^d#Lpvn?2Dlk$N z_s*-4rdMY_I1<#0P9nz^tE-Y@hLOZjhVjGcMTg^ShuF^`dNBQWKKmsIHPkar_POI! zhVvfC3x9P;BIt5vGaVuY3psh)p+QC+6BS~VKFgiJD?^Kt!3%pfrM_5Id%w_>^hTPZ%_HS^WE*S=u{tp-;7(AUR2Jq_2g zq#Yn+Y@aOQfaP2xssXBl*9P6p`L#ptU%jX*Z&6{{dM!Nm}665%jgLWURAYEEN61OHZNWzbV@Wve7;SFJoQIN zAdG_*Z_QC~#%heDFHWC3NebAOFf;3pv7maRqiXpvid3U)e0{~FUE7=nI`l~b)0m`$ zkxlxGqWgU3t1ps_Ac`9F#VWzlhXET#f7wFRlHFk_F{P*Y`fMPG<$Oxf)tlG|koQ}6 zVL9o9nJA%@&$N8u*wZ&xI48Tgfs~A`^&B|_m$L_w_#kbkXh;1iY~wl2&k-;Zvw2Hp zF6qndy6f+9U$Xv-ZNbLihVolKTn~ms2INp{Qnt*ufGH%_DqXLM24n`1v_YdU+f4QZ zDH@Z-o|ms@@b2^(U+Ka$1@DF6unRBvZ&#+TxMrV^QT{c+w!6H7=eft}`az zTrxuvgGLP`KP8c$CEbz~kAVIoDZF$C%E-b9^GdU-sM{$QDj|I|iHqZN* zf9GS1j+sxl;D>7tvN8MQE4+JLBa306217;I4s=Y+_m$0O*&@W9|Hj^}j%RI&59RKf zuCi0}e)US|Z^X2;CN~Dt$kHz7ScdfYDgcq`r;ZJ2i-g!mfQi>v$Ib{Ec}p>c)Uy4Q-9pG zjDERGF2c``U&$z)uXcT9$ltmB!NE1D2lalA-?}Am7~#$L^as6iNHbl_?^h84LtGR z^Oqk5l@2g^v?hM=*HJWt>Cil-1Go8xyp~b;SVX@3WAP^Lo5?Ej z1mL*n-)~iSCjr2>R3Cn`-a}onkRS* z)n{#DRNIm=5BHdt41<%+E?e>cTo*--10S-U(3M4Lnx_CVZ+@l0DN&Jo(vaeU`{7%? zj#JfX_GE>#37s!0io+fE#4PYj)VH7_Cxda@;0J1u8PIl3(jqkzXh$W$0yAP>KJ({a z)d^;cBhiW|lPmq=>#MooG$P60*Ts>~OGo~TS;@m;{u$Suzr@My6DQLzo|H}VK_F3T z!n#GKev3*M_dS>bHa3|-$_&!3af z-VBo+=&D)@Ji*Z*xYk;kuBA!R5q^T$&0H!gz+BH(@zLe(SN}No`{v2s`Td`}rufT# zh6vx*7@!FFZ@z`Hh6CFPNy~@9tZZ6T^21E-RtSBaN%>ovHp4T<~34^9`E`%r7Y4f303I zQqjPJAIKb*2yu&ny#}7}_%+Y}jbPc(=TZSOFR^n)1H5EjSREq#JUe4%`z7#Q zk)|K4t~A2)9=4-usr^`hC7(fMyZ44iFi<mZ$^JFO2HjaBCb-K1)&t-GE z-nRbfe!G6Opc~@eT~g z@B2u(U$;ry)`F!C^>ro&&dfxn(u1?& z-(L2Z$%)!D1qT@LoN4en)CKP;>BqK##)N9X1J9@5REX=rTAV>8&z2GOIqMuwxpA3Z5|Xn@bgjQGndwC{3l%JyPF{j+b_H! z1wTJC3oMPvgXwie>{z%$@uM)G_@|TjOHYueT^#x>uIYrcWn~Q~b2$v96qMVD0bp+K zidhH`SFPh;;(0XveeGoC$LG5f!^7L>#z+>R17zS;9a4l>%D1(xJ|T->=_8V=?E(FJ!XoPKpJgMFL3Q&*ny{4d zGLMYsH!oU{C_~Y(Bgn7g%Tw*W`(WAwIjAfX96ab7$ASg4Z8uK|%A8N+5}d3UQg+SXg)FTeV*8TnE|o*6`(7VqaR=zab_Hn zyp}~MO>wQ6taE3jH!!jrhQak{eCt^l{_dh;gkl?Oy*yXIpRD3H9v2LS{^*YYf!Ji- zyU2am8aIfWMHBCd82*^M{7M&zy#4+$2Kd5iiF}UMNHpr4<(8w)Nn@}0FRqssGJRan z9J)Fz`7y+Ld_HFHIEbWu6{hY$BfL~I)pfWt%*5UeN{Z4A5T^)VM1-i7!Fen6`x}D| zMkXAZxV(QL5C@Sgt2;lhF1!yA-gsqu+Lg^zF5h~9B1G7)h>!J;#MjLWGS1Q-kXgyUB_RkJpMzT`(uf$802v_}>d&BAc;Je>rZQvAm%vZ|_%Nm)Q+V z$4#f{D?>cwCgpQ-jC=dAfUe`2zPn@(H9O~v7AGM`>pwX!EtoE)I2M2Hbs&6)O?Xe# zfKBkn3J-s4bE1Os`-eD*V2Z9Nv>9#-ZJJ9m6U!KMihG$QNkYFUSElpafKEvI`VZ6W z!OZ2F)wJhN(!W=+L@&a>f)e@bTPO7%*r54do1tqvc+!Wn{3UPKKGxo)mkwmFah_DG z8^fD@KI#!1%)E)bK_K-`YFn$>luZz3z*mRnUHqt3{1Eme2>e^rHVHH?Ln{{W1ej+= z%;*_oC4cK~FiUWM&}GBfoxi|G78rjUinSkpXzY&4yZd0BmQauTR`%{%Svmh+YSs#` zst27|hx}i(Y-)tJW>xh~&h+-2A_)R|J%jjEMy(3po|oso0-o+J&nL))Dhf3bBRFyo9u=%zB63k}4?` zaNW#<2&+6(v&Ue$^+5UaE-avTViOY*5_tO{(!K z**kOm=Jd#*ysE)j(7*e!k@!;f*LyxojzS}gva{_zqiuFCPmfuU_!kDXi*25>wg zua71s#Pxn8q&!{iEW*D8btR>Fsg)(UkhJo)&lQ>`w&b^C^J&eBPN%}DAG*C#vsW8@ zm%YOEHsADgR!sLK7DtI_JOHEsp+g=Z7fB$@TRPOJwsaFvB`I~>d)$qMJ-OWwyIE%Q z8CE*Hys-e3f;930bkWe+yFsxq1b*aT+^^yrjCX9T7ivv%4!t-99XUIFOa^T7V*R;2 z#Z*5{8dcbOC^PqqkQ)`z;Ihasm--%0mKScJ=Cfh*ANdTQI#`#BkYKE0gNf|_Tp`N; zW?A6xI?vFbwWp9pZ+QWTm~G8!3y)u+Ua3dS5s9<*F!Hw)|I+A)_SEIxl6?MBO;~yZ z*E7YkQ#@al3-*akq|+Y4NDp1Ezi4cC+n0)e-_x&_Ez>IEVzK|dn!j|_$bI%z z#GLVByb*N(uD96K4GB8Vmkw|5-V?@z_AE`gf`^^$zf@WnaeU=bMdsJ|B!e(QubE4V zVn6wkvuu<6GirY=%^y)D_&=`UlXv( zI0BxFlB*_%Z}8`cs@6^uU7%Fvy)TWOj~jLz+^(#cULk)}!j2c|rL_!NmOoYb!V^?h zobYZge^%NF`h8Nwo_uwms%Y_)>d$@pOO?l^8K(fjgZrwsTSq(eY{B!a;oM9NB(nqk>yS5CRQ})VL6Uv|DE%< zKznDrkds8b3ie6-!2f2kCuz{Rl7C`rPJZgQ`ZI<4Q0U`1JEErZDD*3BptJN#xaMEQ zE})1r_PRlU;Pr*ybXceTWlpJEN;$hocpL8&KYp+nY2NMQ8WUO7{udOX<-Dt_6@^ap_~e#*jrz@x=(cle!j|W>3o3^WBUQPv zPQ+){6Czwr4e@G)_v_XE?|oZDvl66%e*gyvxas0>ckK5~&FQqHo8*S8Wjk}I*YeP3 zUMZd}r7?=oNTUF8M~7#z{Bs8{JiriE?Qia=l)Yyx{A%v`)79(QfC}uOi^U-7(Y2G1 z&`8u3GC!-(#YGxmN+LstNb!t}qUe9r;3KWMvQw2mFP; zt3|d02B1^>J;uM%qv@QMo{5HDXwe|sPGWO2&lDgTcYL{mJG_BP{0}X_@tBf+!P@~l z&n#THgV>GB4aO6!|6KNTg>H6T&gCJ?fcV9r{L*+t0YCcnhp-e16QX}W3a+uE)6lE_ z84mj1J59VZoUDao6`%8nXx@k_$GhyDzdTjG?QCB)kO)s>JlSkt9H25swVGW$9x9$% zw>Uhw+;(a<_;vwY=eh5?uTd>Rp-CeXa{!4Wx5UfehP3{%Y!+l3N9;Y+_<36@A0-NM zh#R>pZseiMp2(b?*vKH3w%CaOak`Q1`1A)c_6f7-n?Ikk=yPKQA(t2J zc6)JIe)_NGW5>NUBRToD4fiORem~7oaVsxAy<)p5TvxM$`~NN*eJ(E7D)8TGwec#c(ViaZ;bnZC1Y({b_bJBOUz0#cY zks;#xu36xfRNWk~wL=^D9;4hF&cRnFOu>1n>%8LRT=kHOio>cn^IM6@)pDSc1d`2Jqt^5{EKw(zpPp?;+;ep!WY@%zoNb$yF zO(nSQoDgps0eh1$vkQC19z^n*SFGqnMT0NuJ>6Y8fP6DpPF#r5+)#KsuOi_|b0z2k zQ#|wutF-*slb&~3U5%}hyqcn!4dBirE4!BeiMec%{;*LpZi)H1wzjt*0}-5wZ&cQ@ zg=^|@4WE6zO`^1TT}1UM`aBR}j6%B6@{5KX!^iiQ!M?wF|F-PV)1e|L@ZI z-vq@IouDLpavv&%QcX46w)f=2_oYGnI-5~1EA9qT>tYvvz`*JY$V!L~>&`ckrsIIy zket>;=7Tz#4cm2V^0v2qn5U}q`gKHQvfbg3jibO96w;jG9qU?ApG4zD*wyQ7!qHc zn+Jg$?96C<)fMVU;qzu>ty-j`Ad@-z^!T5vJPLif=y=-W7x>+>Zgu*_F=C9z^X z<8yZVVN@zmi7DbI9iy9NKE~f2_#?En0Ri8mT_+#u7k|CPuV$TX}Os4wbi+nlYF zNR#9y(7rS#!7^UYlFhQg{!AoJ5knK7mpS$8s|!qB-KdgC(>)e03K~+Tnm zGY40qW!%9zc8BeiqbO^GnqJ$0dHnOEIZL|0LeZl}^B|eq^fA<@zI6NRXD^&9ztNID z>Oa3WotRZ(Z1?9)8;{vFYTCssVeqBxfKC5|Pc&62M<=@WzEMMn zJo?BVIvN|@@1sN%2hDw_bVV-oMubciW?&5+Rtts!mxlP%R|lZ$^gmZfI;Sp?&u1gt zX&`h7i2=+T{S@cGW}A(8FdBVbGTA6PTFXehXNO*t zdFzeH$KdMYIBO%(M_m)~YOD;Cb-2S9Hh+EXe&Wv>T?$_=u0mXxz-+r8U%jr8&*XFV z7EPU6anHF@Xd+yX^qSALhcugoXHvNrzSYyHJqoWje5~29Pwe$PR=2xd_NMh!lJugO z{+qjBbC%7V-||wXZr=762bNgLQ@*cp7?wtZ-I*7;dx0yaxiB%az^S*Hq_&d%4&^GU z#hUHoM092FAaLoH+H-hszw^_xp5R{QU1)t^oN_W*+0*;uSvf2n4!()$jK)&;St$HA zoQ`$0!}y>w4ELmH`8RgUQfZowtp0C)dmyH%n_cr|usj*`5P)kGaCFkqZ29`9f0>=+ z(*1Wo2~SwOO3JIy5Ne`g>fS{MRr51F?!R-I9*v?%_#5311%i^N<78?|!Yvzm`;MNb zs6t!`B>yLIIIQ4?zVg<^BNF9vsEAn&LDmfl3(-}$Hg83jmE#npe*@~^NB`w?1vFW?&JfVVa<43SOS$VgiYm102*Bt1%x%vC+v&~I9 z`h6?#5fUFUjXTO5H8-4u@^Yum#SruAYe|VQG2~8iGxi^%G`R0jaURrGQSHphFvxYy zbz}lU$?!SO+u>f8YMF<3qtDo%J+g^{N~xDktN+gu0zZbyb#ePy2+YAx0d1y`ozCT{ z%1@oYvTQAKW53A~j9jlbCL6U3of>xvYd7LZ4qxn!^7alfe zYkpzG*h7eIkZXI`($W?xOfutc{5j2@2HVtoIzVqX4>418a2OdXU#AOrs)>yWw{W1X z$Lk#tZ71hwYy->I)y9%Crj0nLaiqP^-fg>9ClcmLOWnTQl|{hT-n#P3a`-@$_y8$y zE5&?XF0E!CD>7eO=Qr?AezO}M8{hZrn=4!&eXhdJZ;UI=vT0shdYznU{r{GLgmQBz zc+i5Kf==pkf~d&6k@PE@h0)`GqI6g~qhm6Dg`IasXzCSM3rQ4e~QvGJdk zLG$!EE}{k@ZKp$ex_e9&PDnLcWFvSWoaw8*gkLx`8`Dbr7sH}Y<8|Wjup2L-7iU~7 zf3HwH2IE%o`;KmBgd`^nEhCD3cnc33Wbpj&9F1z&&)Apy7;*w;S!Kf2+OMc|5-xSMcXZd-* zmD0_h%@kbrczmk;`WW{byZG=dp4R92qRg<5Nm>lvKN|mn%C_G{`_{KN0s&{MyR|GX)arIZ`D?pJHX%RtrQU=@Af7XMCpjqUoS1}c@j z_g+aK7k%cS$x1WP;RTIed?K@Md-z#Kd+3UrtTa-B z_&cF!poc@Xh|c4ii@oWs8;`3Sf*k32bKNG;=hd9)YDai|FuPgM>2!rl-yo@sf}GZ4 zJzP-V)#}f)bmmI$I<+%iB6Pv=c+Bh2z1g>R1-0GLz72|@|75iPT^hr_K)s3E_w762 zGY-ixP=rjD=$VV?l^?ofeb0z%L;dOO$PE1SW)GIF&HH?A+GG%e)2wN`=3FNZq1|h@ z6i*;Ho|H~6dU?h`BdYKNrTmKzW%kC&bRm&C$^lPH%aBSgI|j?yrCrG2z~%R+>aUMD zIRTH#sj4A+8ThWYY*xDzy1e--*nmRyX^plnXCUCH@zbRLkEySYi)#DcRuGj|6cmsK z0|lhJk?xj8y1SX7;UXz14bt614k;zlFvJidB@8gsF!a2Kdw=(S-~ESw96rK1d#}Cr zv!3cL)%FE4+?i~j)hkB!Zme=FGKEqC6`tSbPlwmq)BespbwB9t zRohx%`QybnTTPZTE2E2SUp>f#)9@)*J|GM?Igg-V*vg3`!#i*l40!eb!)Ncfzrji} zfVy1Q0%OySI83u-eYcf68z}=~ST5?~EO~DZ2Ub_JLwygvfb)f&H;SYg+NT$7$EL!1 zO&8ZQY>qb`8B~bca6xxgB5L{Qxcc+jZyk)C$c%j`R@Uc$oEQbrs1l@B_&1j_U>8^-|0sqH7{` zt7cJnpILd{q_lcGCWEhZ z?MM0dq>9bIP9PgRdI9tqza5&wfTYKYsGE`S_Q6-6n(JIlZ!lF7-txWDgQp8XFFXn3 z(;bDcyS>I+!xwde!ywyDDk3wg%ZZvputSK%vCgym=iKuId0~PiP}F6?mr0 zt$f`gaQRIXctDsJFN{jqUW|{1NiJ55TCKc1n=-b^fAWBByd@vI2u9;?7wx%pWAH0K z$5|i4_cmA%T+e^ zJ8a;cjB3IQ8b~Rc#Zyn&-&g+4c#4tB(qZ{)k^MdYcXo@d)60yzm{e2;7jf)?XYT=q z#}jvFc=QDR2{;HMP6`!_sTnVWI}Ep*t{U-*e(-tsb?btL7R~*Y9r8(R94m314{W;2 zS_j)LJc7{D_R6hYUPtra=ybu!^rHZ2Eq~>VNwtAg_5pR$+#(leK2M zihC8bBA5pBDrH&EAaoi#Udq{9QIg_jxR)u55#huZihgu3SBSq;`v$&kP~=!oNyfb0 z^kP}7L>sf5*{o!RKMQ;C4T_Ud<%6M<`e(NP`Pb;%YhG{5_`>P&U-&>6bPp&+XUklu z=Muu@MYUZRwTpk@sm4su5Ld*7CS#zU!Ag5?h0Hq~y7Qd(#`Ujq5mgl>oq{4BG#l-j zLknU1V_u1tbBW@4=NdG~*p|J=7;wJQ#b6!*@{^6g+v$Jq&;jIohvdkN^fS;mijpre z2A;nT7%|t!VU#+oZPB~^l_deor0)dQhY>e>sR2*U`cU}2`ZrhiJ%BJC=;0gz8Y3ir zjt|s^n4IiCcTcP3qP%NT{iETS==-;)Mm}uVR(ezh5&_}`o0 zQSr9CY(B!wukR%)uwShe>2X=<`GSNE(epr|usSyQoXIwQJ;anz8cAxQ4SWmpR_LW>X`v08x6`bj$;)z>s#}>ON36uPEqH z?Q{P?sWFCp%G78$lg~K_e6`nm0XIs1*JG+dw5EUfV#9$z6df@(fMOEAc2ZQdJL3t_ z_v2q|yV5H+X5H;(>Bu?j@i_UZW6a)obE{7K>!$7F_2J6_p5LuXN>Ej$3QJ3>|4r)E`d` zAi7C&yit!b>#;wsuE^_HYsrv`@N15o>eyVp@aX_5R&5~kN`{O(U~4U*{vVNPrl?4a zYv9e;tWl%^=F3J9vAyQ}(2P2r156@Jmq(+IX~`|~};jaNQ;_&q7n0W0nQKk3A` z&`dm`&^X5}yr}j1-v-w?UBkr)ifHqb}h%_fn zBgk-4s^5xO@mDd;cu7Z`EkSr6uqi^{(*M=EHFJ(V(g;49ot93wMPQ>kC~PZAqh3qk zzLvOm0xyc$*Zh8Rkkda#mF9aR_2h}I`czM?xxq{U8M(rDY_r42zoa=HDMibKzv{<+ zvAYrI#P6by9K)b%54QKCY~5cw+UO?h7r<{A-#gTFDPlW)-=0>H;Rqor0$-=C3}<%m zg0Eb#Ph>=zVAeI+QN5kMul!GVk!3pCx!369l`E6=YEcy1-FoqJ#bJI-EKtWa<4|_; zCrx|U|3CdgQeX7M61*NNiH88>wb)|-@3pk%D2Ds-i?yBzqon^tV_V(0|9Qt=GyxQs z2daUp@W9h^)tT3a6?Bb(s)zkn8BThXpF>+K=je8eH1*#{_`^{aoP~Ozk(WQbq2DAs zd~PZ$DjuR;&5%D#@*l%C?yr6tA-Hgj-vcOB=H*Se`$whamFoka%iv6)!!Tj?2o>xK zps>sC5q-RwiMt5|Usd+@b3A)-dc8L`_LvRh`3$9gjoR&l3= z^ZR^K(oe-#cnuZ{bt;LTPdF55erHal6lA_h-P+|8D&*v|auQhb%XyHXPVtpP<;Cl) zc*RJ5C7U;4ukSq!ZQ$dIbwmG1{`LLzGh5xeAw4T-LKa`Fxk8<}!V&sd$SI|wk&%U^ zl1YC;Mbx9-^4-^5mF&VOmnmJ19Mw;X*)GW+zdfT!;6u?jw$C7+a9`*v-*3(q8Ga68 zo%Ir6)YM0grpDivv0-2KmBaY&BUwBUWvA~ zW#nfr(4P^0ntbKzwX)g1U;22hPSThyEzp}fRqEs(D1+#t(yY1((Yv%MXsM1-ak4d5 zctE;;eekN5(p9V3>#Bf+T-i(by^iIgfH;o`ME|z~eM|`0+AE}lE;SaHyRj;pL$4nM zk)pXw`*fU+kfyu{rMK&uW^Z-N=B(z*k4t=7C$bD)SiG5hoWBoMnHk#wrz(6dUGv>< z>OX-ml}QPC4-dpmWuclCyz#7KVFR9Qa+o9kwP9TwYP67T4*KvqKH1dFj9ygkeCTrWb;>tlF@-p5!Siv~%mB~7m$m9Qo%KG($|%rY&h zK^*QaJ9l}N`Ta?^!~bm9%E>tX_;X9NEnG>f3mrO8F0t(!(A2a$ab)U*+*86~*ZSqX zO2Y8sXi3ZAhqG#s{KhXos|{kxou1<2Mfb*^H$99WPh#GXH;&vl;eO#%FEZz8AhPHw zK@ri-KrE?3kXXTg4HcG03#)jDTuEEHC1t|-nISQ*^D_9}%hpX)^z zE9=`AI|F?eLtb8bF~#uSRgFdwX2r}Oh}3-(yAge>_0vmB0`DN%#A^NQii3gz+_p=X zN$6Jf8R(glE^ndcUjXZ3Jk7T+)cM9D@z`Q9CXC|{^65wh`Gehm`5}T9 zLX?7gPIbv5Q{D$iWlL|~^uCx=z*0S{;0q(v!*3U}3vI)atn@hcRW5QP7Yq#sE zJm{@#t1J$lbpIZ}u6Z5Ct)l>TIf^S>Ahrb8zgtWxuM+&?K~WK`K7!}|9o#)N@s#4k ztAmRMcd%PWuOcO}8*Hpw+GQe?*S(tClkgVYK>Om9YBbl$=@mMQIBunS*lylHN%F?Z_+JFl21ypv^!dHTF)bun zzC=2bIN%w#Hrr4gnnhVFNxy5F_LSpGhGmE00K9)mp!fGQb7xo7{&*_0x`wyaOa9=- z^@#A@0x0D5LcLW1eYv`kc4;%!MTxZfAy*lz5u+Ix-zqg`#C2^uO z=bBc>vO*kDO7+=1vXYZhVLn=S1cX}kNuLmYEOoZ+U6w^yt!#cICFvM7OsE^+@E2Y) zmo?-rRBhi9{4|QJcJQLLg_ml}%{acnzV}8;vdR`Y;tmbzi15rwYy!LJD#N&ko#Bm* zM#~r!Zp$U+BFdCNPNt{b0}1|?5#X3`5trdh;Y&DlmwC<)EjpU&W1N}v81NZ{1Mr_7 zE6b)Qj)Pj4+dYNh1$x_BINFzCfmJ4;k4$78QRjldFIPQq_FOkB=|1;=0*r#ii`I>BP8T~mzc1Fz<93t@ zc;GUexEIbx0fOr2ZkS$>~mOKB|dLk?Hpn#j}e4n)L3?KZ!#j3f5 zqZh05S?4~eMl+tbQ@8E;FRCf39VG}m`=7>*GotFuxqT@8uQEqO>xVuL4;Py=o_fQ) zD%9okvvd-;)igw~zD-i(eB8>A@9|%VLoK>)`-kXLGF(+@iKJp8-6NyMHxZ&jycMR# zf^$q60R~STwYBc9bJeu7+_kaUW)hLA@_Xa zOp=3WdGZ&M6Rqh7RMV<7zN!HaN{BBAATv5)ek&MbrJeP_OTSunwJ`tLMjD{1(*F&D zCZXrMu5I>duhOAXyQ=FLga(GJuF4V7#tD`?;KWm!BI{d;$RxDa0D!E-!!vqv zV_>f@WEH-_hY(3|_mFwY^-zFeZgUJf!Q zDpf@mbBiDng+-R;J%wj^fAOftB=o}hGAI(Qwx41DV6G`i2ceq zEb2Fvcl(yQ#$}4mTb^VU#}>OcpqV)xvvOyV4g@*cm#6w{FXVU5v=GJNco+M=Gw!iz z_sQQ(BNwM=+(QRKGi1U<-*KGwf2Yi2`+E0S1;Mg(el7gVt0EBU<5FWCQO zrbrs{z>)jMq{(oI;Xa<#-Q6SA_a$x9Kk5F2)`b{4S^*7b;s|M2CIlO!y{kDq419|I z^&j7E9+w7}u33>0>GN^DIP>VA+YU?3qS>wK4FYni55QTacx|5UO-)9bMJ0E28-I~S z!xY;T2uK$QA9xOYkZAp|`pfaGFg{6%IUdW(s0^#Uwj^+8Vx@8DaL*_bQneHVZLQDd zf3myx#dvqe3*2zu*h;iEJ@yQ>DG9a_*=*8NzUTMAcWps>)<9HSTgat+k&ms3$EMnH z<$y|qZcyU^>)-@51~zo9Gzr_Cjrg{KMvu*+mTC?|t5C0}6axZDMZ{FugFHfU~uMbdNIr^-i%#<{62zph*X)oo~sjqaYxA%?{G{w(?PK31pg&o;A9$UXBc0h8^RVyNqp zSiQGC_V25ARHN>%dph}Ziz}P-)Gy^M7#7kv9ih_UXo@!JaL6RMnZ<4!Eq7t*t44*)@NfwJ|+>j(sPd4*-Cg zKYzu5dk-4XMS89J9#b~CCQjm|!>v9WTD=PpAx(kGDljtN)?*p{8%HiIEx@O8v1!wd zd@7t`gvMC36cT~TDkdvBuAO}~Hu)h2Fq!sGMR+%5CT8B5HpCGDDpWSf#{>H2p~tcX zl{#U*8aF+VUldRwXI3{OHb1tr5#Y3(15|mEtxZhh$Q$oV5a<1w#q!`*DwZJcSS8Tm zips1O+>w}6KwESL)ny}$x8S1&iSAz(f)ay>#41nYvAA$4@YomvI4U?=P@3TQ)w2KOb8nMhrVL9AS1^Ve3Ej#>A|f#S?O0;l|tDs zjYwZE-$Y3Q2tpxmExXI9EG})IwjI3HWEF;u6f_dC1ZoMtI=Pn)BD4zat)vSOlOmMS zv6IgM3L-fRN?s4F&=18||I%7rp5R?FvGKuCU{Q$yqV<0UE%TP)8vgvjXpN;;DVkm= z`29?)Jv=Xotd^j2+z5bdxD3CdlHR=b#0`(Au2ndNPSYzzT&rz8OKM)f=wwMQjpA%F z^nCBD7bQABW$H`W8f{cRIjLD59MQDsljVV!t(tm3xqH2aD6Y`o&lF;G__6jXIlMQ7 zxkguA`w1Y*5Bsh3yl}x14`Psc%qwoQjR%JIaYRhG=@l9XJ3y1hd3VS4|kG z@k;1T7XOTUa*Up0^S}Atz#AJnIEjw7lz->`)p0y6{dzlbl3A8vp3n#&N~SfvH6Kn` z^e8MI4~tMv_3>lFyE@H(mFoA>h?_WTWX>Z=xMoD2j{Q~K7a7sZkl zd4dRRvGcs5(Rv;Qi)m7R&GzQ4>`=$eam31$RX~mVxOl(!&t??G{0vq4($yNp8)}W$ z_^HnmY#du1GAq141qpquHFOnI5p$J6yAMi0p*E~6JA2d%OSIeHf}sFlehKLc)l*zF7iK{DvBuZ)zjRR(DeN}hbssH%LJ*`z(^IY@PM zZt=Rr*=dMS1GW+Kwz5HpyVv#Izu-S!$zG|xj`5Xk32fn(K*E~%Zp6s{(s-B`KxB;3 zfovqCoT^hU9SZN=)8p=$V^WB0M5i8mfUBBLVVG_^DsZD#)-COlznS#0RWZFVV+u3H zeNhqiL>;VOrl!e%B_8tg@;9R#FKPComV?oi&l<63L~+{lqbwmrnf-NFpq^8l0p3Y^ z!rh}P=El|qkWMDjf$;l`eMZSbmeokWWpx{YlLGC&3DA%{Bcl$bx;Lg0;5A_3(H0>h z^bEbxdAu&+^E<=IV1m99tljN4!xD}^yO?yu1Q)KZ~K2l{AfLKr0*e$V&Pm6Yte ze|P(yRpZehR#U+bzv}7P_JdyH2Y5x{g#vT%wO1=kAE&%quj@Scv}RwRH?po(0=z@u z7ZU;J(B(^SHO)aCDqbK+a7E|4ER7UIw?P=QuLI`v?JLoCidO1*!5w=tN=^49;~u2z z6UaTDS+IN12IG767F0a?kN6qzT(W_~KFA*_6~Ee5GTbT~hjfjb7Fj%B4|MQQc`Wrybm+->2ESo?2PqaNqqJNmxU|0 zMV#iaQw|T(tdv+p$3DYqd;x0G-mi#5P7>_0G8RkIf_xUO)~E4njRwoimk{|{p)n99RymJo;( z%5p0w4vTwJ5~p}WwS!>}a6y0^VGIKT%37Uo_x!0Y=HvWf>z(gL=Ts6)yDB){w}@rS zove8tSE+@$uvkT8!jHG)bgX2X+USF{1g-VK#@W<6Ckm-6Oon$y(vZ&rGAwcQf=LKA z5m_;NqZ<&WwFZNBO_^gX*NxlCrhjr_yc zD*Nw5eeAYL6l9dd>VN{FW_hMu@;>VzM_^aE)N5k|?fx_pQ@!GF)< z@I<^}k+y&|^BC2Vp7SPkX$}@!GKRJm18Trg$kF|ZGS^gyj-Q(s76Ba@lMOrLK2V@+ z18AVTHkXVg<(6|0PVu+75{1joxlOOmxHaj_g-4GsvUA2SNRyfiuHZUDbK8eFaT*^S zkT6bh8?DM#fO&EipzY{a4Y<4P&Yp^yVkx>rI;yVLD&l?B2fn6aAuDIF!)x^Oxl4Y7 z{^~e{u2+h?h}GcJcY<^9?)mrDfIZ`#ZEHp)sop~}(%q=7+Fh!jd$`y}fB5&9nKf6o z%)$f&D%&UNQNJf9j|{ZOZ8@W&?RrNb9IoH}_q9D8Dv9I56pEQhPlN-?mM)gY(3ICK z`4Tn5)JiI+9XD&1Ziqx0;8CLDSMaL3BzN$D{gKv4*DarrUBpa_0jSxvkMZ$EKu_A2!tA^87oivTsJ7))Ee3rIUf#%GISywocjfKUoc#CI1DSKR*AO z_39Vd=Ubn1HKt5ExdhE#hZK#-U`^J{z8V?0(jJa9K|XSdi*|Ub9QOOr=col4m;Bqs zC&97uRfzVnT4z;HyOPY+s^{{mCn{+IM$8kSCSS$uu3%YXyCPx-g>IC1n5%?Lfay$R z!`0}%L!Gk7oD_b2_IYKSaq{XdWEhI^kK#w;&r)zGo_4N08v8^nXyy=rAL@S-Rou1! zN*y^)v$6<1bSL%-z(?H!0g)f=hL>Uzc}@mxqSXMH!sC>HhwU7 zr_VWlE~H;`cdj^(ds`hpCUyP!2c(9>(s>HaFdvQ+{VdRV=-ws-!od5pR=bI8%ojwk|Een{;!>!4IX1cR0CQ+@J%p!n#*?o`XWR(V)NrBKtU*^k zBN{q2e(~AMFMYJ+|HM^57<_jQ0y5BAv&2tzC?_+Hi++FWD?ddrGY;_iEtdm+Gy&*& zHl$veriR@?rDUjniF{V!gK5h?iqFT(yrr2Jp9)PXd87{hbV`w9#(_dI=a=ZVPCdfm z@ol|R6tm;C?+{FOYEn8Na>ktqG zw;m=A#~TnmEob|vveG$KwgR`7(ziU0vs+*9#^*qu%5n7ZL-H4$$`2cKcrlCSR4Xg* zHV0ySt7$#j;cof2`>Ly^PG<4J9^jS&?JewlxYI)!_2)jd@lLZ%=qQ&%%o%Yb_3K_m zP&LID9qz^6xkCUHyk}InX0O!qr-|k{o{AGd<##%yQg)~_myWv+I#FF3wkg-}e%j>y zVZQTwI&{NdiH`qTJc3IQ4w*e23Fo!>slVSos>*g49@5n3Ks@7wbp6hjLvmFGH+sXO4%(D8mBHj+onuaU=X6 zNH$IvsefBt&i3GIxXk>i>m0*aZmyVj6NdpuTn*QW>JFf}KP;(u-Fhi%=I0ge4Htzv zyI^LvGOWsbybJoAF_6END^2(4qZ&yBcN5pAWlA~vtc!JAMcBPGyesgC&L+I8l zHc4oGl1XqcqzltM?ZA$aKrEGzw_pxz!mYI}i?OMZP(P}^wPW+u04gg&o<+*t8kR-} zAUXDN8GL1+4WUB-CMjL?w2%KNs0m z*@Ndij|16c*!%BF@(0ujv*e`g;o8glJCSJP-_M^UCsq(0TP^k65!-RxxhnO1JK^jU zm)@kTfcJ-31jDQDt0ivWC0|)gv7C|=n)&R%Kw2yl@9M5bU3AehPzZ;!01s#?o48GLr&amDk87(5C6${N`eTe4A|(CsGJ z`Euf&g>$) zIL>LExDxrXVb<~<=(c0uUK}1;M13Q+4Y#o^O;ZN}{eyIDaBOjNl|Las#oX3J#mjq*7A40Hwb1H4{%p;;>~*@@ zM*WqNsF^t2_6Ujy%J`WYa5AAPl2f+Q0#K0uH@@3!T-hS#uhCyWlF`n9mV=o{e2m|3 zZCLwNhZ>yTdXD=5y1K6r)~gwK*sY82&gC)GVQdf|Qr+;QISmIkhrmbG4W$Na-R6XC zJhp{Re|3lZ`r&(Ad=R(}-+8nj8;sH{1dG$J4yW(e=KI;oUzEQ8x?n^sm)ZThbU(pa zR-lvbuv*zhgd{#3D#Cvp#8wFRYz_;~qa%D%ema4|98}?T_q(+TcP}@(meP5INcprs z124sQt11=Ibb9D@0*EM~B0C-l>?8}FM)Fw;def2n*Q8r@%)4#Bs!CzIVNXcFitW#? zHmd`)-@=WB>=~VFxq~&?v(zR)zH;cZR)YOB!V8g zWRs2u)s~BmYCwk*42k!Jf&Vr~IU$yZQaViRJ(}}UZwJxMc*ne+jhAJNC=#Mmvj517 zCr;iD0_#n&*Hwm20=uaO1rnvV=>&2-=9AWq0h*yZF?sS0Ce`c7$@YJ2QQ9Yle5B~r zTDI$#i|v;{U@Xp?&)fz{uLFW1601Ze5V zrh3`=+lYV~oDtx?X0%lK#BDD{7-e~zI5n|g&i(ECHY*S}1y+#iZ*TN8!wG1QTu!TIn^ z2;j)%z%Go#)Vno>`K1b2%XfRL!#Q`DNc4;th9b(D4L;;k6Q2vjNU?Iw7}9fgek4O5 z^*-9wV#`%*nO>ZCYu&nXR~2s>#_B*~E(-in@F^z4-vsFNQQbG71#SR0$KWIP;kFNg zHzrsM^b{XF+1FaGtm=Hutf|xtvh+fGz=v5{&rs3T9^5B zrCVPHk<`Fu`oBRi>9yrp>f?#wKy^sB$}3Fv9r)mDJ=QE-{|d-~2uC1OX_e2Fwbj&e z^#FvBJMk;Z{XOGky0z@iR}x%7Eq+N*-FsW>y4>$fv!iTvRoNOPaal&*>~ru`ybDM+ zo^0n1^5&1KtcjF7qMV%kgmZpe&J3*QujC||)@jnyIhhkn(vQt<-^9^- zT$Nt;KCv+JK?|JN&F62p0t`2!ILyrWA||`%pskf=2OYgICj564O&)#!R#QuRDWub8 zUtT#xG9;36jK1{WLV9Vq4!T{Y3R}o<;Izn0m1&QFeF|?6&iw9Y+a>~L=~5IRtu@;g zMwzfI&GAyNn$uG2+2Ua6EDLi=X_SIiiC5SAG=P@BQ$z9D7A1V4*TzM2s32pe(-5WU zPTZ)>y|flAwO_s(UEW&kC`bRZ2!;U&S`V1$i?bI8M>Yhfr;D9B8R3;H!lOQ2_O z`e7=1=9iWl9qKO70^nC(o%bR?dLTgyD{Ch5Nw8%{V$Vj8ioLBmS0KGjW8bWEb9V8D zyTzVLV+p94Erhn}$v-?9S=C;Xq{*f%(>89zlv--{K<5XNWD#{2T{5i_9hPW^uk4%U zTkjh&LNj9?gPSz7q3G>4nwZPEhMTPwC*CYGS{Sm4YE*R$+tKPLLS!ud?X1$?%1-YS z>XvrU^M6f`wy>4UAwpr-p5SaJ-J#sIurGlDHp}7#_k7LU3nkKThyf;FJ@~#c0S;-P zI@?n+kDOT26AmU4=N()@pNpS5rmJs*6Pa|jJ~mzT>O#E@vI~0Bhy~XFIKj-a43ezJBvd$8nhZ$S@SfCwltx8P! zTlXysJt%_F^YikNow|Ru*{fK%A=h`!$!i62c9*;+f!3QP9rMkFufKEy+}sop*A@V6 zSqUCM{hpKHTB4|HODqtV*&liMjUBIVnwxuTBW10|dDBdsj=uy>-~0~VaM-1=e^RtC zN*&p7qOD-beM0oQy4l)KCt_^rvK`nf8-RE%#I_Fv;LlY{Jtu|S&OR7lKF5!97o6u# zolfEJ{J7>N5W~W!g)83)U?PY8h9Qm*mA{XU3{>nCpUPi`i81TzX?fSH*V$vF6vL&c z$C@P|*d+;rwbn14$s3)@UamG1i=o;%kg;+c7MA8sB0l2@AfWOjCE(4m4W^T1ql9nm zVf`IYfftw)PuH6i9SiyGi_Jdw`pnL?Ex~|+jD)`IN~l$cwP)D+Yj_HG`Ici9kX?%> zImaS^X1}ja>$2cE5tigeFJD}{_zLtue|#T%79n$N+L?LN^^E9>2nOgDIc`;Xh!`&@ zD8{f3Sx9E%3X@C-s4avv*@_!7q;`;ryd{mEopsL=Kzpll?9rmtQ+-sf=Wi;kLq&_yo;{GF3ew;qxs-vU7WA7n^&BVYw5h<_W7Mbmq>qFx*4UlWDs8?X?2&`s$Rep6V`MgtyiKU*~tGAqal?ox_f2YzFQ7j3r`=0z*q= znufz;cJkrV*$uc$-yrVQ- zvAmDH>H*wFDh2*S+UQ>N@MLfqDH>3uDX^+nLOn1OpTI|XWAWch;|uT#V*etW_6Icx zS~nIVrV4E@OI66U2fm8huNqkZUc{wQfX%PLz!BKp1dTF|aOUNd62jRc&LZ4+a)QVg z1Epsa%&5i7_}f?QdU&f@%$v{i9dd0yBmfrV%MK9k@F8m#9EV)zNsg%AtQtjZx5th6 zbpwm=RUz=F=Z6E^s|q!Kaw7+!KTV!h{7y`d_qE`XP-nG(cRD{F+DH=WIb{2T+y#tk zwB*e7iI^ALe#_ublI#oDl+#r?SJ&;O>G5mvp0xD>ybsPGR*@8i*UVwnf>$EHuA

?9E6rtuX?vg%r|Zhx!3Il0jnQ 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 KMNUMnLSTZB7tN&r literal 0 HcmV?d00001 diff --git a/src/leapfrogai_ui/src/lib/components/ChatSidebar.svelte b/src/leapfrogai_ui/src/lib/components/ChatSidebar.svelte new file mode 100644 index 000000000..3143600f0 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/components/ChatSidebar.svelte @@ -0,0 +1,325 @@ + + + +
+ + + +
+ +
+ {#each dateCategories as category} + + {#if organizedConversations[category]} + {#each organizedConversations[category] as conversation (conversation.id)} + {@const editMode = editConversationId && editConversationId === conversation.id} +
+ conversationsStore.changeConversation(conversation.id)} + > + + +
+ {/each} + {/if} +
+ {/each} +
+ (deleteModalOpen = false)} + on:open + on:close + on:submit={handleDelete} + >Are you sure you want to delete your {activeConversation?.label.substring(0, MAX_LABEL_SIZE)} chat? + + +
+ + + diff --git a/src/leapfrogai_ui/src/lib/components/ChatSidebar.test.ts b/src/leapfrogai_ui/src/lib/components/ChatSidebar.test.ts new file mode 100644 index 000000000..b4c079075 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/components/ChatSidebar.test.ts @@ -0,0 +1,309 @@ +import { ChatSidebar } from '$components'; +import { + mockDeleteConversation, + mockDeleteConversationError, + mockEditConversationLabel, + mockEditConversationLabelError +} from '$lib/mocks/chat-mocks'; +import { conversationsStore, toastStore } from '$stores'; +import { render, screen, within } from '@testing-library/svelte'; +import userEvent from '@testing-library/user-event'; +import { fakeConversations } from '../../testUtils/fakeData'; +import { vi } from 'vitest'; +import stores from '$app/stores'; + +const { getStores } = await vi.hoisted(() => import('../../lib/mocks/svelte')); + +const editConversationLabel = async ( + oldLabel: string, + newLabel: string, + keyToPress = '{enter}' +) => { + const overflowMenu = within(screen.getByTestId(`side-nav-menu-item-${oldLabel}`)).getByRole( + 'button', + { name: /menu/i } + ); + await userEvent.click(overflowMenu); + const editBtn = within(overflowMenu).getByRole('menuitem', { name: /edit/i }); + await userEvent.click(editBtn); + const editInput = screen.getByLabelText('edit conversation'); + await userEvent.clear(editInput); + await userEvent.type(editInput, newLabel); + await userEvent.keyboard(keyToPress); +}; + +vi.mock('$app/stores', (): typeof stores => { + const page: typeof stores.page = { + subscribe(fn) { + return getStores({ + url: `http://localhost/chat/${fakeConversations[0].id}`, + params: { conversation_id: fakeConversations[0].id } + }).page.subscribe(fn); + } + }; + const navigating: typeof stores.navigating = { + subscribe(fn) { + return getStores().navigating.subscribe(fn); + } + }; + const updated: typeof stores.updated = { + subscribe(fn) { + return getStores().updated.subscribe(fn); + }, + check: () => Promise.resolve(false) + }; + + return { + getStores, + navigating, + page, + updated + }; +}); + +describe('ChatSidebar', () => { + it('renders conversations', async () => { + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversationsSection = screen.getByTestId('conversations'); + + fakeConversations.forEach((conversation) => { + expect(within(conversationsSection).getByText(conversation.label)).toBeInTheDocument(); + }); + }); + + it('deletes conversations', async () => { + mockDeleteConversation(); + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversationsSection = screen.getByTestId('conversations'); + + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + expect(within(conversationsSection).getByText(fakeConversations[1].label)).toBeInTheDocument(); + + const overflowMenu = screen.getAllByLabelText('menu')[0]; + await userEvent.click(overflowMenu); + + const deleteBtn = within(overflowMenu).getByText('Delete'); + await userEvent.click(deleteBtn); + + const modal = screen.getByRole('presentation'); + + expect(modal).toBeVisible(); + + const confirmDeleteBtn = within(modal).getByText('Delete'); + await userEvent.click(confirmDeleteBtn); + expect(modal).not.toBeVisible; + + expect( + within(conversationsSection).queryByText(fakeConversations[0].label) + ).not.toBeInTheDocument(); + expect(within(conversationsSection).getByText(fakeConversations[1].label)).toBeInTheDocument(); + }); + it('dispatches a toast when there is an error deleting a conversation and it does not delete the conversation from the screen', async () => { + mockDeleteConversationError(); + + const toastSpy = vi.spyOn(toastStore, 'addToast'); + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversationsSection = screen.getByTestId('conversations'); + + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + + const overflowMenu = screen.getAllByLabelText('menu')[0]; + await userEvent.click(overflowMenu); + + const deleteBtn = within(overflowMenu).getByText('Delete'); + await userEvent.click(deleteBtn); + + const modal = screen.getByRole('presentation'); + + expect(modal).toBeInTheDocument(); + + const confirmDeleteBtn = within(modal).getByText('Delete'); + await userEvent.click(confirmDeleteBtn); + + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + expect(toastSpy).toHaveBeenCalledTimes(1); + }); + + it('edits conversation labels', async () => { + const newLabelText = 'new label'; + mockEditConversationLabel(); + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversationsSection = screen.getByTestId('conversations'); + + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + + await editConversationLabel(fakeConversations[0].label, newLabelText); + expect(within(conversationsSection).getByText(newLabelText)).toBeInTheDocument(); + }); + + it('edits conversation labels when tab is pressed instead of enter', async () => { + const newLabelText = 'new label'; + mockEditConversationLabel(); + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversationsSection = screen.getByTestId('conversations'); + + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + + await editConversationLabel(fakeConversations[0].label, newLabelText, '{Tab}'); + expect(within(conversationsSection).getByText(newLabelText)).toBeInTheDocument(); + }); + + it('edits conversation labels when the user clicks away from the input (onBlur)', async () => { + const newLabelText = 'new label'; + mockEditConversationLabel(); + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversationsSection = screen.getByTestId('conversations'); + + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + + const overflowMenu = within( + screen.getByTestId(`side-nav-menu-item-${fakeConversations[0].label}`) + ).getByRole('button', { name: /menu/i }); + await userEvent.click(overflowMenu); + const editBtn = within(overflowMenu).getByRole('menuitem', { name: /edit/i }); + await userEvent.click(editBtn); + const editInput = screen.getByLabelText('edit conversation'); + await userEvent.clear(editInput); + await userEvent.type(editInput, newLabelText); + + await userEvent.click(document.body); + + expect(within(conversationsSection).getByText(newLabelText)).toBeInTheDocument(); + }); + + it('dispatches a toast when there is an error editing a conversations label and it does not update the label on the screen', async () => { + mockEditConversationLabelError(); + const toastSpy = vi.spyOn(toastStore, 'addToast'); + + const newLabelText = 'new label'; + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversationsSection = screen.getByTestId('conversations'); + + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + + await editConversationLabel(fakeConversations[0].label, newLabelText); + await userEvent.keyboard('{enter}'); + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + expect(toastSpy).toHaveBeenCalledTimes(1); + }); + + it('does not update the conversation label when the user presses escape and it removes the text input', async () => { + const newLabelText = 'new label'; + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversationsSection = screen.getByTestId('conversations'); + + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + + await editConversationLabel(fakeConversations[0].label, newLabelText, '{escape}'); + + expect(screen.queryByLabelText('edit conversation')).not.toBeInTheDocument(); + expect(within(conversationsSection).getByText(fakeConversations[0].label)).toBeInTheDocument(); + }); + + it('disables the input when enter is pressed', async () => { + const newLabelText = 'new label'; + mockEditConversationLabel(); + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + // Not using the helper function b/c we need to reference the editInput at the end + const overflowMenu = screen.getAllByLabelText('menu')[0]; + await userEvent.click(overflowMenu); + const editBtn = within(overflowMenu).getByText('Edit'); + await userEvent.click(editBtn); + const editInput = screen.getByLabelText('edit conversation'); + await userEvent.clear(editInput); + await userEvent.type(editInput, newLabelText); + await userEvent.keyboard('{enter}'); + expect(editInput).toHaveProperty('readOnly', true); + }); + + it('edits the correct conversation label when different edit buttons are pressed', async () => { + const newLabelText1 = 'new label 1'; + const newLabelText2 = 'new label 2'; + + mockEditConversationLabel(); + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + const conversation1 = screen.getByTestId(`side-nav-menu-item-${fakeConversations[0].label}`); + const conversation2 = screen.getByTestId(`side-nav-menu-item-${fakeConversations[1].label}`); + + expect(within(conversation1).getByText(fakeConversations[0].label)).toBeInTheDocument(); + expect(within(conversation2).getByText(fakeConversations[1].label)).toBeInTheDocument(); + + await editConversationLabel(fakeConversations[0].label, newLabelText1); + await editConversationLabel(fakeConversations[1].label, newLabelText2); + + expect(within(conversation1).getByText(newLabelText1)).toBeInTheDocument(); + expect(within(conversation2).getByText(newLabelText2)).toBeInTheDocument(); + }); + + it('removes the edit input when the focus on the input is lost', async () => { + mockEditConversationLabel(); + const newLabelText = 'new label'; + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatSidebar); + + await editConversationLabel(fakeConversations[0].label, newLabelText, '{tab}'); + const editInput = screen.queryByText('edit conversation'); + expect(editInput).not.toBeInTheDocument(); + }); +}); diff --git a/src/leapfrogai_ui/src/lib/components/PoweredByDU.svelte b/src/leapfrogai_ui/src/lib/components/PoweredByDU.svelte new file mode 100644 index 000000000..fa990f760 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/components/PoweredByDU.svelte @@ -0,0 +1,28 @@ + + +
+ Doug + Powered By + Defense Unicorns +
+ + diff --git a/src/leapfrogai_ui/src/lib/components/Toasts.svelte b/src/leapfrogai_ui/src/lib/components/Toasts.svelte new file mode 100644 index 000000000..780ffc639 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/components/Toasts.svelte @@ -0,0 +1,34 @@ + + +{#if $toastStore.toasts} +
+ {#each $toastStore.toasts as toast (toast.id)} +
+ toastStore.dismissToast(toast.id)} + /> +
+ {/each} +
+{/if} + + diff --git a/src/leapfrogai_ui/src/lib/components/index.ts b/src/leapfrogai_ui/src/lib/components/index.ts new file mode 100644 index 000000000..f818cf655 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/components/index.ts @@ -0,0 +1,3 @@ +export { default as ChatSidebar } from './ChatSidebar.svelte'; +export { default as PoweredByDU } from './PoweredByDU.svelte'; +export { default as Toasts } from './Toasts.svelte'; diff --git a/src/leapfrogai_ui/src/lib/constants/index.ts b/src/leapfrogai_ui/src/lib/constants/index.ts new file mode 100644 index 000000000..5fe94c08c --- /dev/null +++ b/src/leapfrogai_ui/src/lib/constants/index.ts @@ -0,0 +1 @@ +export const MAX_LABEL_SIZE = 100; diff --git a/src/leapfrogai_ui/src/lib/helpers/dates.test.ts b/src/leapfrogai_ui/src/lib/helpers/dates.test.ts new file mode 100644 index 000000000..6395ddc8b --- /dev/null +++ b/src/leapfrogai_ui/src/lib/helpers/dates.test.ts @@ -0,0 +1,178 @@ +import { dates } from '$helpers'; +import { getFakeConversation } from '../../testUtils/fakeData'; + +describe('date helpers', () => { + describe('isToday', () => { + it('returns true when two dates are the same day', () => { + const date1 = new Date('2022-01-01'); + const date2 = new Date('2022-01-01'); + expect(dates.isToday(date1, date2)).toBe(true); + }); + + it('returns false when two dates are different days', () => { + const date1 = new Date('2022-01-01'); + const date2 = new Date('2022-01-02'); + expect(dates.isToday(date1, date2)).toBe(false); + }); + + it('returns false when two dates are different months', () => { + const date1 = new Date('2022-01-01'); + const date2 = new Date('2022-02-01'); + expect(dates.isToday(date1, date2)).toBe(false); + }); + + it('returns false when two dates are different years', () => { + const date1 = new Date('2022-01-01'); + const date2 = new Date('2023-01-01'); + expect(dates.isToday(date1, date2)).toBe(false); + }); + }); + + describe('getNumMonthsAgo', () => { + it('returns the correct number of months ago', () => { + const currentDate = new Date(); + const pastDate = new Date(currentDate.getFullYear() - 1, currentDate.getMonth() - 3); + const expectedMonthsAgo = 15; + + expect(dates.getNumMonthsAgo(pastDate)).toBe(expectedMonthsAgo); + }); + + it('returns 0 when the past date is the same as the current date', () => { + const currentDate = new Date(); + const pastDate = new Date(currentDate); + const expectedMonthsAgo = 0; + + expect(dates.getNumMonthsAgo(pastDate)).toBe(expectedMonthsAgo); + }); + + it('returns a negative number when the past date is in the future', () => { + const currentDate = new Date(); + const futureDate = new Date(currentDate.getFullYear() + 1, currentDate.getMonth() + 3); + const expectedMonthsAgo = -15; + + expect(dates.getNumMonthsAgo(futureDate)).toBe(expectedMonthsAgo); + }); + }); + + describe('getDateCategory', () => { + it('returns "Old" when the date is more than the default set for numMonthsAgo', () => { + const currentDate = new Date(); + const pastDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 5); + const expectedCategory = 'Old'; + + expect(dates.getDateCategory(pastDate)).toBe(expectedCategory); + }); + + it('returns "Today" when the date is the same as the current date', () => { + const currentDate = new Date(); + const expectedCategory = 'Today'; + + expect(dates.getDateCategory(currentDate)).toBe(expectedCategory); + }); + + it('returns "Yesterday" when the date is one day before the current date', () => { + const currentDate = new Date(); + const yesterday = new Date( + currentDate.getFullYear(), + currentDate.getMonth(), + currentDate.getDate() - 1 + ); + const expectedCategory = 'Yesterday'; + + expect(dates.getDateCategory(yesterday)).toBe(expectedCategory); + }); + + it('returns "This Month" when the date is in the same month as the current date', () => { + const currentDate = new Date(); + const sameMonthDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 10); + const expectedCategory = 'This Month'; + + expect(dates.getDateCategory(sameMonthDate)).toBe(expectedCategory); + }); + + it('returns the formatted month and year when the date is in a different year', () => { + // Date to compare against needs to be within numMonthsToDisplay months but still + // within previous year in order to see the monthname - year + // we are setting the numMonthsToDisplay to 1200 to make sure it does not put the month in 'Old' category + + // The system timezone here is behind UTC so you need to specify T00:00 to make sure it reflects the local + // day properly and doesn't show October when it should be November 1 + const date = new Date('2023-11-01T00:00'); + const expectedCategory = 'November - 2023'; + + expect(dates.getDateCategory(date, 1200)).toBe(expectedCategory); + }); + + it('returns the formatted month when the date is in the current year', () => { + // We can't use actual today because if this test is run in January, the previous month + // will get the year with its category (e.g December - 2023) and the test will fail + const todayOverride = new Date('2024-03-01T00:00'); + const date = new Date('2024-02-01T00:00'); + const expectedCategory = 'February'; + + expect(dates.getDateCategory(date, 4, todayOverride)).toBe(expectedCategory); + }); + }); + + describe('organizeConversationsByDate', () => { + const todayOverride = new Date('2024-03-20T00:00'); + + it('organizes conversations by date category', () => { + const conversations = [ + // today + getFakeConversation({ insertedAt: todayOverride.toDateString() }), + // Yesterday + getFakeConversation({ + insertedAt: new Date( + todayOverride.getFullYear(), + todayOverride.getMonth(), + todayOverride.getDate() - 1 + ).toDateString() + }), + getFakeConversation({ + insertedAt: new Date( + todayOverride.getFullYear(), + todayOverride.getMonth(), + todayOverride.getDate() - 1 + ).toDateString() + }), + // This Month + getFakeConversation({ + insertedAt: new Date( + todayOverride.getFullYear(), + todayOverride.getMonth(), + 10 + ).toDateString() + }), + // February + getFakeConversation({ + insertedAt: new Date(new Date('2024-02-01T00:00')).toDateString() + }), + // December - 2023 + getFakeConversation({ + insertedAt: new Date(new Date('2023-12-01T00:00')).toDateString() + }), + // Old + getFakeConversation({ + insertedAt: new Date( + todayOverride.getFullYear(), + todayOverride.getMonth() - 5 + ).toDateString() + }) + ]; + console.log(conversations.map((c) => c.inserted_at)); + + const expectedOrganizedConversations = { + Today: [conversations[0]], + Yesterday: [conversations[1], conversations[2]], + 'This Month': [conversations[3]], + February: [conversations[4]], + 'December - 2023': [conversations[5]], + Old: [conversations[6]] + }; + + const result = dates.organizeConversationsByDate(conversations, todayOverride); + expect(result).toEqual(expectedOrganizedConversations); + }); + }); +}); diff --git a/src/leapfrogai_ui/src/lib/helpers/dates.ts b/src/leapfrogai_ui/src/lib/helpers/dates.ts new file mode 100644 index 000000000..4eb227e89 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/helpers/dates.ts @@ -0,0 +1,181 @@ +const formatOptions: Intl.DateTimeFormatOptions = { + month: 'long' +}; + +/** + * Calculates the number of months between a past date and the current date. + * @param pastDate The past date to compare against the current date. + * @returns The number of months between the past date and the current date. + */ +export const getNumMonthsAgo = (pastDate: Date) => { + const currentDate = new Date(); + const currentYear = currentDate.getFullYear(); + const currentMonth = currentDate.getMonth(); + + const pastYear = pastDate.getFullYear(); + const pastMonth = pastDate.getMonth(); + + const yearDiff = currentYear - pastYear; + const monthDiff = currentMonth - pastMonth; + + return yearDiff * 12 + monthDiff; +}; + +/** + * Returns the category of a given date based on its proximity to the current date. + * Categories include 'Today', 'Yesterday', 'This Month', the 'month name' and/or 'month name - year', and 'Old' + * @param {Date} date - The date to categorize. + * @param {number} [numMonthsToDisplay=4] numMonthsToDisplay - How many months to go back before putting in 'Old' category + * @param {Date} [today=new Date()] today - The current date. Defaults to the current date. + * @returns The category of the date. + */ + +// function formatDate(someDateTimeStamp) { +// var dt = new Date(someDateTimeStamp), +// date = dt.getDate(), +// month = months[dt.getMonth()], +// timeDiff = someDateTimeStamp - Date.now(), +// diffDays = new Date().getDate() - date, +// diffMonths = new Date().getMonth() - dt.getMonth(), +// diffYears = new Date().getFullYear() - dt.getFullYear(); +// +// if(diffYears === 0 && diffDays === 0 && diffMonths === 0){ +// return "Today"; +// }else if(diffYears === 0 && diffDays === 1) { +// return "Yesterday"; +// }else if(diffYears === 0 && diffDays === -1) { +// return "Tomorrow"; +// }else if(diffYears === 0 && (diffDays < -1 && diffDays > -7)) { +// return fulldays[dt.getDay()]; +// }else if(diffYears >= 1){ +// return month + " " + date + ", " + new Date(someDateTimeStamp).getFullYear(); +// }else { +// return month + " " + date; +// } +// } + +/** + * Checks if two dates are the same day. + * @param d1 - The first date. + * @param d2 - The second date. + * @returns True if the dates are the same day, false otherwise. + */ +export const isToday = (d1: Date, d2: Date) => { + return ( + d1.getDate() === d2.getDate() && + d1.getMonth() === d2.getMonth() && + d1.getFullYear() === d2.getFullYear() + ); +}; + +/** + * Checks if the first date is exactly one day before the second date. + * + * @param {Date} firstDate - The first date to be compared. + * @param {Date} secondDate - The second date to be compared. + * @returns {boolean} - Returns true if the first date is exactly one day before the second date, false otherwise. + */ +function isOneDayBefore(firstDate: Date, secondDate: Date): boolean { + // Set both dates to midnight to ensure we're only comparing the dates, not the times + const first = new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate()); + const second = new Date(secondDate.getFullYear(), secondDate.getMonth(), secondDate.getDate()); + + // Calculate the difference in milliseconds between the two dates + const diff = second.getTime() - first.getTime(); + + // Check if the difference is exactly 24 hours + return diff === 24 * 60 * 60 * 1000; +} + +export const getDateCategory = (date: Date, numMonthsToDisplay = 4, today = new Date()) => { + // How many months to go back before putting in 'Old' category + const dateToCheck = new Date(date); + + const yearsDiff = Math.abs(dateToCheck.getFullYear() - today.getFullYear()); + const monthsDiff = getNumMonthsAgo(dateToCheck); + + if (monthsDiff > numMonthsToDisplay) return 'Old'; + + if (isToday(dateToCheck, today)) { + return 'Today'; + } + + if (isOneDayBefore(dateToCheck, today)) { + return 'Yesterday'; + } + + if (yearsDiff === 0 && dateToCheck.getMonth() === today.getMonth()) { + return 'This Month'; + } + + if (yearsDiff > 0) { + if (monthsDiff <= numMonthsToDisplay) { + // Ex. November - 2023 + return `${dateToCheck.toLocaleString('en-US', formatOptions)} - ${dateToCheck.getFullYear()}`; + } + } else return dateToCheck.toLocaleString('en-US', formatOptions); +}; + +/** + * Organizes an array of conversations by date category. + * + * @param {Conversation[]} conversations - The array of conversations to be organized. + * @param {Date} [today=new Date()] today - The current date. Defaults to the current date. + * @returns An object containing conversations grouped by date category. + */ +export const organizeConversationsByDate = (conversations: Conversation[], today = new Date()) => { + const result: { [category: string]: Conversation[] } = {}; + for (const conversation of conversations) { + const dateCategory = getDateCategory( + new Date(conversation.inserted_at), + undefined, + today + ) as keyof typeof result; + !result[dateCategory] + ? (result[dateCategory] = [conversation]) + : result[dateCategory].push(conversation); + } + return result; +}; + +/** + * Sorts an array of months in reverse order. + * Months can be in the format "MonthName" or "MonthName - Year". If the year is omitted, the current year is assumed. + * e.g. "March - 2023" or "January". + * + * @param {string[]} months - The array of months to be sorted. Each month string should follow the + * format "MonthName - Year" or "MonthName", where "MonthName" is the full name of the month. + * @returns {string[]} The sorted array of months in reverse chronological order. + */ +export const sortMonthsReverse = (months: string[]) => { + const monthOrder = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ]; + + return months.sort((a, b) => { + const [monthA, yearA = new Date().getFullYear().toString()] = a.split(' - '); + const [monthB, yearB = new Date().getFullYear().toString()] = b.split(' - '); + + const monthIndexA = monthOrder.indexOf(monthA); + const monthIndexB = monthOrder.indexOf(monthB); + + const yearComparison = parseInt(yearB) - parseInt(yearA); + + if (yearComparison === 0) { + return monthIndexB - monthIndexA; + } + + return yearComparison; + }); +}; diff --git a/src/leapfrogai_ui/src/lib/helpers/index.ts b/src/leapfrogai_ui/src/lib/helpers/index.ts new file mode 100644 index 000000000..2515271b2 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/helpers/index.ts @@ -0,0 +1 @@ +export * as dates from './dates'; diff --git a/src/leapfrogai_ui/src/lib/mocks/chat-mocks.ts b/src/leapfrogai_ui/src/lib/mocks/chat-mocks.ts new file mode 100644 index 000000000..8deb033b7 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/mocks/chat-mocks.ts @@ -0,0 +1,100 @@ +import { http, HttpResponse, delay } from 'msw'; +import { faker } from '@faker-js/faker'; +import { server } from '../../../vitest-setup'; + +type MockChatCompletionOptions = { + responseMsg?: string[]; + withDelay?: boolean; + delayTime?: number; +}; +export const mockChatCompletion = ( + options: MockChatCompletionOptions = { + responseMsg: ['Fake', 'AI', 'Response'], + withDelay: false, + delayTime: 0 + } +) => { + const encoder = new TextEncoder(); + + server.use( + http.post('/api/chat', async () => { + if (options.withDelay) { + await delay(options.delayTime); + } + const stream = new ReadableStream({ + start(controller) { + options.responseMsg?.forEach((msg) => controller.enqueue(encoder.encode(msg))); + controller.close(); + } + }); + return new HttpResponse(stream, { headers: { 'Content-Type': 'text/plain' } }); + }) + ); +}; + +export const mockChatCompletionError = () => { + server.use( + http.post('/api/chat', async () => { + return new HttpResponse(null, { status: 500 }); + }) + ); +}; + +// export const mockNewChatSubmission = (fakeConversation: Conversation, fakeMessage: Message) => { +// server.use( +// http.post('/', () => { +// return HttpResponse.json({ +// type: 'success', +// status: 200, +// // Svelte form actions return data in a weird format that uses templating to build the object +// // not sure how to easily replicate this yet without hard coding the values like this +// data: `[{"newConversation":1},{"id":2,"user_id":3,"label":4,"inserted_at":5,"messages":6},"${fakeConversation.id}","${fakeConversation.user_id}","${fakeConversation.label}","${fakeConversation.inserted_at}",[7],{"id":8,"user_id":3,"conversation_id":2,"role":9,"content":4,"inserted_at":10},"${fakeMessage.id}","user","${fakeMessage.inserted_at}"]` +// }); +// }) +// ); +// }; + +export const mockNewConversation = () => { + server.use( + http.post('/api/conversations/new', () => { + return HttpResponse.json({ + id: faker.string.uuid(), + user_id: faker.string.uuid(), + label: faker.lorem.words(5), + inserted_at: new Date().toLocaleString() + }); + }) + ); +}; + +export const mockNewMessage = (fakeMessage: Message) => { + server.use( + http.post('/api/messages/new', () => { + return HttpResponse.json({ message: fakeMessage }); + }) + ); +}; + +export const mockDeleteConversation = () => { + server.use( + http.delete('/api/conversations/delete', () => new HttpResponse(null, { status: 204 })) + ); +}; + +export const mockDeleteConversationError = () => { + server.use( + http.delete('/api/conversations/delete', () => new HttpResponse(null, { status: 500 })) + ); +}; + +export const mockEditConversationLabel = () => { + server.use( + http.put('/api/conversations/update/label', () => new HttpResponse(null, { status: 204 })) + ); +}; + +export const mockEditConversationLabelError = () => { + server.use( + http.put('/api/conversations/update/label', () => new HttpResponse(null, { status: 500 })) + ); +}; diff --git a/src/leapfrogai_ui/src/lib/mocks/svelte.ts b/src/leapfrogai_ui/src/lib/mocks/svelte.ts new file mode 100644 index 000000000..0d74cf9ac --- /dev/null +++ b/src/leapfrogai_ui/src/lib/mocks/svelte.ts @@ -0,0 +1,35 @@ +import { type Readable, readable } from 'svelte/store'; +import type { Navigation, Page } from '@sveltejs/kit'; +import { fakeConversations } from '../../testUtils/fakeData'; +import { faker } from '@faker-js/faker'; + +type GetStoresOverrides = { + url: string; + params: Record; +}; +export const getStores = ( + options: GetStoresOverrides = { url: 'http://localhost', params: {} } +) => { + const navigating = readable(null); + const page = readable({ + url: new URL(options.url), + params: options.params, + route: { id: null }, + status: 200, + error: null, + // TODO - the profile and session types are incompletely mocked out + data: { + conversations: fakeConversations, + profile: {}, + session: { user: { id: faker.string.uuid() } } + }, + state: {}, + form: null + }); + const updated: Readable & { check(): Promise } = { + subscribe: readable(false).subscribe, + check: () => Promise.resolve(false) + }; + + return { navigating, page, updated }; +}; diff --git a/src/leapfrogai_ui/src/lib/stores/conversations.ts b/src/leapfrogai_ui/src/lib/stores/conversations.ts new file mode 100644 index 000000000..f0391799f --- /dev/null +++ b/src/leapfrogai_ui/src/lib/stores/conversations.ts @@ -0,0 +1,100 @@ +import { writable } from 'svelte/store'; +import { MAX_LABEL_SIZE } from '$lib/constants'; +import { goto } from '$app/navigation'; + +type ConversationsStore = { + conversations: Conversation[]; +}; + +const defaultValues: ConversationsStore = { + conversations: [] +}; + +const createConversationsStore = () => { + const { subscribe, set, update } = writable({ ...defaultValues }); + return { + subscribe, + set, + update, + setConversations: (conversations: Conversation[]) => { + update((old) => ({ ...old, conversations })); + }, + changeConversation: async (newId: string | null) => { + await goto(`/chat/${newId}`); + }, + newConversation: async (label: string) => { + const res = await fetch('/api/conversations/new', { + method: 'POST', + body: JSON.stringify({ label: label.substring(0, MAX_LABEL_SIZE) }), + headers: { + 'Content-Type': 'application/json' + } + }); + if (res.ok) { + const newConversation = { ...(await res.json()), messages: [] }; + update((old) => { + return { + ...old, + conversations: [...old.conversations, newConversation] + }; + }); + await goto(`/chat/${newConversation.id}`); + } + }, + + newMessage: async (conversation_id: string, content: string, role: 'system' | 'user') => { + const res = await fetch('/api/messages/new', { + method: 'POST', + body: JSON.stringify({ + role, + content, + conversation_id + }), + headers: { + 'Content-Type': 'application/json' + } + }); + if (res.ok) { + const responseMessage = await res.json(); + + update((old) => { + const updatedConversations = [...old.conversations]; + const conversationIndex = old.conversations.findIndex((c) => c.id === conversation_id); + const oldConversation = old.conversations[conversationIndex]; + + updatedConversations[conversationIndex] = { + ...oldConversation, + messages: [...oldConversation.messages, responseMessage] + }; + return { + ...old, + conversations: updatedConversations + }; + }); + } + }, + deleteConversation: async (id: string) => { + update((old) => ({ + ...old, + conversations: old.conversations.filter((c) => c.id !== id) + })); + await goto('/chat'); + }, + updateConversationLabel: (id: string, newLabel: string) => + update((old) => { + const updatedConversationIndex = old.conversations.findIndex((c) => c.id === id); + const updatedConversation = { ...old.conversations[updatedConversationIndex] }; + updatedConversation.label = newLabel; + + const updatedConversations = [...old.conversations]; + updatedConversations[updatedConversationIndex] = updatedConversation; + + return { + ...old, + conversations: updatedConversations + }; + }) + }; +}; + +export default createConversationsStore(); diff --git a/src/leapfrogai_ui/src/lib/stores/index.ts b/src/leapfrogai_ui/src/lib/stores/index.ts new file mode 100644 index 000000000..da9a14ec2 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/stores/index.ts @@ -0,0 +1,2 @@ +export { default as conversationsStore } from './conversations'; +export { default as toastStore } from './toast'; diff --git a/src/leapfrogai_ui/src/lib/stores/toast.ts b/src/leapfrogai_ui/src/lib/stores/toast.ts new file mode 100644 index 000000000..d78057cc2 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/stores/toast.ts @@ -0,0 +1,48 @@ +import { writable } from 'svelte/store'; +import { v4 as uuidv4 } from 'uuid'; +import type { ToastNotificationProps } from 'carbon-components-svelte/src/Notification/ToastNotification.svelte'; + +const defaultValues: ToastStore = { + toasts: [] +}; + +const toastDefaults: Pick = { + kind: 'info', + caption: new Date().toLocaleString(), + timeout: 3000 +}; +const createToastsStore = () => { + const { subscribe, update } = writable({ ...defaultValues }); + + return { + subscribe, + addToast: (toast: RequiredToastFields & OptionalToastFields) => { + const id = uuidv4(); + const newToast: ToastNotificationProps = { + id, + ...toastDefaults, + ...toast + }; + update((old) => ({ + ...old, + toasts: [...old.toasts, newToast] + })); + + // Remove toast after timeout + setTimeout(() => { + update((old) => ({ + ...old, + toasts: old.toasts.filter((toast) => toast.id !== id) + })); + }, newToast.timeout); + }, + dismissToast: (id: string) => { + update((old) => ({ + ...old, + toasts: old.toasts.filter((toast) => toast.id !== id) + })); + } + }; +}; + +export default createToastsStore(); diff --git a/src/leapfrogai_ui/src/lib/supabaseClient.ts b/src/leapfrogai_ui/src/lib/supabaseClient.ts new file mode 100644 index 000000000..bc75f623f --- /dev/null +++ b/src/leapfrogai_ui/src/lib/supabaseClient.ts @@ -0,0 +1,4 @@ +import { createClient } from '@supabase/supabase-js'; +import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'; + +export const supabase = createClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY); diff --git a/src/leapfrogai_ui/src/lib/types/conversations.d.ts b/src/leapfrogai_ui/src/lib/types/conversations.d.ts new file mode 100644 index 000000000..1fccd731d --- /dev/null +++ b/src/leapfrogai_ui/src/lib/types/conversations.d.ts @@ -0,0 +1,29 @@ +type Conversation = { + id: string; + label: string; + user_id: string; + messages: Message[]; + inserted_at: string; +}; + +type Message = { + id: string; + role: 'user' | 'system'; + user_id: string; + conversation_id: string; + content: string; + inserted_at: string; +}; + +type AIMessage = { + role: 'user' | 'system'; + content: string; +}; + +type ChatRequest = { + key: string; + messages: AIMessage[]; + model: string; + max_tokens: number; + temperature: number; +}; diff --git a/src/leapfrogai_ui/src/lib/types/toast.d.ts b/src/leapfrogai_ui/src/lib/types/toast.d.ts new file mode 100644 index 000000000..c90da5577 --- /dev/null +++ b/src/leapfrogai_ui/src/lib/types/toast.d.ts @@ -0,0 +1,6 @@ +type ToastStore = { + toasts: ToastNotificationProps[]; +}; + +type RequiredToastFields = Pick; +type OptionalToastFields = Partial>; diff --git a/src/leapfrogai_ui/src/routes/+layout.server.ts b/src/leapfrogai_ui/src/routes/+layout.server.ts new file mode 100644 index 000000000..b2448f1a7 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/+layout.server.ts @@ -0,0 +1,7 @@ +import type { LayoutServerLoad } from './$types'; + +export const load: LayoutServerLoad = async ({ locals: { getSession } }) => { + return { + session: await getSession() + }; +}; diff --git a/src/leapfrogai_ui/src/routes/+layout.svelte b/src/leapfrogai_ui/src/routes/+layout.svelte new file mode 100644 index 000000000..7f5adf84f --- /dev/null +++ b/src/leapfrogai_ui/src/routes/+layout.svelte @@ -0,0 +1,31 @@ + + + + LeapfrogAI{$page.data.title ? ` - ${$page.data.title}` : ''} + + + + diff --git a/src/leapfrogai_ui/src/routes/+layout.ts b/src/leapfrogai_ui/src/routes/+layout.ts new file mode 100644 index 000000000..9f055e242 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/+layout.ts @@ -0,0 +1,29 @@ +import { env } from '$env/dynamic/public'; +import type { LayoutLoad } from './$types'; +import { createBrowserClient, isBrowser, parse } from '@supabase/ssr'; + +export const load: LayoutLoad = async ({ fetch, data, depends }) => { + depends('supabase:auth'); + + const supabase = createBrowserClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_SUPABASE_ANON_KEY, { + global: { + fetch + }, + cookies: { + get(key) { + if (!isBrowser()) { + return JSON.stringify(data.session); + } + + const cookie = parse(document.cookie); + return cookie[key]; + } + } + }); + + const { + data: { session } + } = await supabase.auth.getSession(); + + return { supabase, session }; +}; diff --git a/src/leapfrogai_ui/src/routes/+page.server.ts b/src/leapfrogai_ui/src/routes/+page.server.ts new file mode 100644 index 000000000..be76bba06 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/+page.server.ts @@ -0,0 +1,13 @@ +import { redirect } from '@sveltejs/kit'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ url, locals: { getSession } }) => { + const session = await getSession(); + + // if the user is already logged in return them to the account page + if (session) { + throw redirect(303, '/chat'); + } + + return { url: url.origin }; +}; diff --git a/src/leapfrogai_ui/src/routes/+page.svelte b/src/leapfrogai_ui/src/routes/+page.svelte new file mode 100644 index 000000000..a226cf1fd --- /dev/null +++ b/src/leapfrogai_ui/src/routes/+page.svelte @@ -0,0 +1,48 @@ + + + + + diff --git a/src/leapfrogai_ui/src/routes/api/chat/+server.ts b/src/leapfrogai_ui/src/routes/api/chat/+server.ts new file mode 100644 index 000000000..c4d1240d6 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/api/chat/+server.ts @@ -0,0 +1,53 @@ +import OpenAI from 'openai'; +import { + PUBLIC_DEFAULT_MODEL, + PUBLIC_DEFAULT_SYSTEM_PROMPT, + PUBLIC_DEFAULT_TEMPERATURE, + PUBLIC_LEAPFROGAI_API_BASE_URL +} from '$env/static/public'; +import { env } from '$env/dynamic/private'; +import { OpenAIStream, StreamingTextResponse } from 'ai'; +import { messagesSchema } from '../../../schemas/chat'; +import { error } from '@sveltejs/kit'; + +// Set the runtime to edge for best performance +export const config = { + runtime: 'edge' +}; + +// This endpoint is called by the Vercel AI SDK handleSubmit function +export async function POST({ request }) { + + const openai = new OpenAI({ + apiKey: env.LEAPFROGAI_API_KEY, + baseURL: PUBLIC_LEAPFROGAI_API_BASE_URL + }); + + let messages: AIMessage[]; + + try { + const body = await request.json(); + messages = body.messages; + } catch (e) { + error(400, { message: 'Bad Request' }); + } + if (!messages) error(400, { message: 'Bad Request' }); + + const validMessages = await messagesSchema.isValid(messages); + + if (!validMessages) error(400, { message: 'Bad Request' }); + + // Add the default system prompt to the beginning of the messages + messages.unshift({ content: PUBLIC_DEFAULT_SYSTEM_PROMPT, role: 'system' }); + + const response = await openai.chat.completions.create({ + model: PUBLIC_DEFAULT_MODEL, + temperature: Number(PUBLIC_DEFAULT_TEMPERATURE), + max_tokens: 1000, + stream: true, + messages: messages + }); + + const stream = OpenAIStream(response); + return new StreamingTextResponse(stream); +} diff --git a/src/leapfrogai_ui/src/routes/api/chat/server.test.ts b/src/leapfrogai_ui/src/routes/api/chat/server.test.ts new file mode 100644 index 000000000..6f0c30a77 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/api/chat/server.test.ts @@ -0,0 +1,27 @@ +import { afterAll } from 'vitest'; +import { POST } from './+server'; + +describe('/api/chat', () => { + beforeAll(() => { + vi.mock('openai'); + }); + afterAll(() => { + vi.restoreAllMocks(); + }); + + it('returns a 400 when messages are missing from the request', async () => { + const request = new Request('http://localhost:5173/api/chat', { + method: 'POST', + body: JSON.stringify({ messages: [{ break: 'me' }] }) + }); + + await expect(POST({ request })).rejects.toMatchObject({ status: 400 }); + }); + it('returns a 400 when messages are incorrectly formatted', async () => { + const request = new Request('http://localhost:5173/api/chat', { + method: 'POST' + }); + + await expect(POST({ request })).rejects.toMatchObject({ status: 400 }); + }); +}); diff --git a/src/leapfrogai_ui/src/routes/api/conversations/delete/+server.ts b/src/leapfrogai_ui/src/routes/api/conversations/delete/+server.ts new file mode 100644 index 000000000..96d8817ae --- /dev/null +++ b/src/leapfrogai_ui/src/routes/api/conversations/delete/+server.ts @@ -0,0 +1,18 @@ +import { error, json } from '@sveltejs/kit'; + +export async function DELETE({ request, locals: { supabase } }) { + const requestData = await request.json(); + + const id: string = requestData.conversationId; + + const { error: responseError } = await supabase.from('conversations').delete().eq('id', id); + + if (responseError) { + console.log( + `error deleting conversation, error: ${responseError?.code}: ${responseError?.message}` + ); + error(500, 'Error deleting conversation'); + } + + return json({ message: 'success' }); +} diff --git a/src/leapfrogai_ui/src/routes/api/conversations/new/+server.ts b/src/leapfrogai_ui/src/routes/api/conversations/new/+server.ts new file mode 100644 index 000000000..d8546f837 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/api/conversations/new/+server.ts @@ -0,0 +1,35 @@ +import { error, json, redirect } from '@sveltejs/kit'; + +export async function POST({ request, locals: { supabase, getSession } }) { + const { label } = await request.json(); + const session = await getSession(); + + if (!session) { + throw redirect(303, '/'); + } + + const conversation: Omit = { + label, + user_id: session.user.id + }; + + // TODO validate input + // TODO if there is an error, the chats continue to stream, but they are not saved + // Can we trigger another call on error that retries the save? + // At least send user a toast to let them know it was not saved (same for new message endpoint) + + const { error: responseError, data: createdConversation } = await supabase + .from('conversations') + .insert(conversation) + .select() + .returns(); + + if (responseError) { + console.log( + `error creating conversation, error: ${responseError.code}: ${responseError.message}` + ); + error(500, { message: 'Internal Server Error' }); + } + + return json(createdConversation[0]); +} diff --git a/src/leapfrogai_ui/src/routes/api/conversations/update/label/+server.ts b/src/leapfrogai_ui/src/routes/api/conversations/update/label/+server.ts new file mode 100644 index 000000000..951f75e8d --- /dev/null +++ b/src/leapfrogai_ui/src/routes/api/conversations/update/label/+server.ts @@ -0,0 +1,21 @@ +import { error } from '@sveltejs/kit'; + +export async function PUT({ request, locals: { supabase } }) { + const { id, label } = await request.json(); + + // TODO - for validation, ensure max length MAX_LABEL_SIZE + + const { error: responseError } = await supabase + .from('conversations') + .update({ label: label }) + .eq('id', id); + + if (responseError) { + console.log( + `error updating conversation, error: ${responseError?.code}: ${responseError?.message}` + ); + error(500, { message: 'Internal Server Error' }); + } + + return new Response(null, { status: 204 }); +} diff --git a/src/leapfrogai_ui/src/routes/api/messages/new/+server.ts b/src/leapfrogai_ui/src/routes/api/messages/new/+server.ts new file mode 100644 index 000000000..00a91df24 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/api/messages/new/+server.ts @@ -0,0 +1,27 @@ +import { error, json, redirect } from '@sveltejs/kit'; + +export async function POST({ request, locals: { supabase, getSession } }) { + const session = await getSession(); + + if (!session) { + throw redirect(303, '/'); + } + const requestData = await request.json(); + + const message: Omit = { ...requestData, user_id: session.user.id }; + + // TODO validate message input + + const { error: responseError, data: createdMessage } = await supabase + .from('messages') + .insert(message) + .select() + .returns(); + + if (responseError) { + console.log(`error creating message, error: ${responseError.code}: ${responseError.message}`); + error(500, { message: 'Internal Server Error' }); + } + + return json(createdMessage[0]); +} diff --git a/src/leapfrogai_ui/src/routes/auth/+page.server.ts b/src/leapfrogai_ui/src/routes/auth/+page.server.ts new file mode 100644 index 000000000..9b5a02dc4 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/auth/+page.server.ts @@ -0,0 +1,12 @@ +import type { Actions } from '../../../.svelte-kit/types/src/routes/$types'; +import { redirect } from '@sveltejs/kit'; + +export const actions: Actions = { + signout: async ({ locals: { supabase, getSession } }) => { + const session = await getSession(); + if (session) { + await supabase.auth.signOut(); + throw redirect(303, '/'); + } + } +}; diff --git a/src/leapfrogai_ui/src/routes/auth/callback/+server.ts b/src/leapfrogai_ui/src/routes/auth/callback/+server.ts new file mode 100644 index 000000000..74903caf5 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/auth/callback/+server.ts @@ -0,0 +1,12 @@ +// src/routes/auth/callback/+server.ts +import { redirect } from '@sveltejs/kit'; + +export const GET = async ({ url, locals: { supabase } }) => { + const code = url.searchParams.get('code'); + + if (code) { + await supabase.auth.exchangeCodeForSession(code); + } + + throw redirect(303, '/chat'); +}; diff --git a/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+layout.svelte b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+layout.svelte new file mode 100644 index 000000000..de6adbb44 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+layout.svelte @@ -0,0 +1,75 @@ + + + + {conversationLabel || $page.data.title} + + + + +
+ + + + + + +
+ + + + diff --git a/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+page.server.ts b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+page.server.ts new file mode 100644 index 000000000..adbed1682 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+page.server.ts @@ -0,0 +1,34 @@ +import { error, redirect } from '@sveltejs/kit'; +import type { PageServerLoad } from './$types'; +export const load: PageServerLoad = async ({ locals: { supabase, getSession } }) => { + const session = await getSession(); + + if (!session) { + throw redirect(303, '/'); + } + + const { data: profile, error: profileError } = await supabase + .from('profiles') + .select(`username, full_name, website, avatar_url`) + .eq('id', session.user.id) + .single(); + + const { data: conversations, error: conversationsError } = await supabase + .from('conversations') + .select( + `id, label, user_id, inserted_at, messages (id, role, user_id, conversation_id, content, inserted_at)` + ) + .eq('user_id', session.user.id) + .returns(); + + if (profileError) { + console.log(`error getting user profile: ${JSON.stringify(profileError)}`); + await supabase.auth.signOut(); + } + if (conversationsError) { + console.log(`error getting user conversations: ${JSON.stringify(conversationsError)}`); + error(500, { message: 'Error loading conversations' }); + } + + return { title: 'LeapfrogAI - Chat', session, profile, conversations: conversations ?? [] }; +}; diff --git a/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+page.svelte b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+page.svelte new file mode 100644 index 000000000..9a98c5864 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+page.svelte @@ -0,0 +1,202 @@ + + + +
+ + +
+
+ {#each $messages as message (message.id)} +
+ {#if message.role === 'user'} +
+ +
+ {:else} + LeapfrogAI + {/if} + {message.content} +
+ {/each} +
+ +
+
+
+
+ +
+ +
+
+
+
+ + diff --git a/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/ChatPageWithToast.test.svelte b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/ChatPageWithToast.test.svelte new file mode 100644 index 000000000..d03854d24 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/ChatPageWithToast.test.svelte @@ -0,0 +1,9 @@ + + +
+ + +
diff --git a/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/chatpage.test.ts b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/chatpage.test.ts new file mode 100644 index 000000000..43ad83939 --- /dev/null +++ b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/chatpage.test.ts @@ -0,0 +1,176 @@ +import { render, screen } from '@testing-library/svelte'; +import { conversationsStore } from '$stores'; + +import { + fakeConversations, + getFakeConversation, + getFakeMessage +} from '../../../testUtils/fakeData'; +import ChatPage from './+page.svelte'; +import ChatPageWithToast from './ChatPageWithToast.test.svelte'; +import userEvent from '@testing-library/user-event'; +import stores from '$app/stores'; +import { vi } from 'vitest'; + +import * as navigation from '$app/navigation'; + +import { + mockChatCompletion, + mockChatCompletionError, + mockNewConversation, + mockNewMessage +} from '$lib/mocks/chat-mocks'; +import { delay } from 'msw'; + +const { getStores } = await vi.hoisted(() => import('../../../lib/mocks/svelte')); + +describe('The Chat Page', () => { + it('changes the active chat thread', async () => { + const goToSpy = vi.spyOn(navigation, 'goto'); + + const fakeConversation = getFakeConversation({ numMessages: 6 }); + + conversationsStore.set({ + conversations: [fakeConversation] + }); + + render(ChatPage); + + expect(screen.queryByText(fakeConversation.messages[0].content)).not.toBeInTheDocument(); + + await userEvent.click(screen.getByText(fakeConversation.label)); + + expect(goToSpy).toHaveBeenCalledTimes(1); + expect(goToSpy).toHaveBeenCalledWith(`/chat/${fakeConversation.id}`); + }); + + it('it renders all the messages', async () => { + vi.mock('$app/stores', (): typeof stores => { + const page: typeof stores.page = { + subscribe(fn) { + return getStores({ + url: `http://localhost/chat/${fakeConversations[0].id}`, + params: { conversation_id: fakeConversations[0].id } + }).page.subscribe(fn); + } + }; + const navigating: typeof stores.navigating = { + subscribe(fn) { + return getStores().navigating.subscribe(fn); + } + }; + const updated: typeof stores.updated = { + subscribe(fn) { + return getStores().updated.subscribe(fn); + }, + check: () => Promise.resolve(false) + }; + + return { + getStores, + navigating, + page, + updated + }; + }); + + conversationsStore.set({ + conversations: fakeConversations + }); + + render(ChatPage); + + // TODO - the $messages from useChat are not getting populated by setMessages so this test fails + // The test does show that the conversation_id and activeConversation are being set correctly + for (let i = 0; i < fakeConversations[0].messages.length; i++) { + await screen.findByText(fakeConversations[0].messages[0].content); + } + }); + + describe('chat form', () => { + const question = 'What is AI?'; + const fakeConversation = getFakeConversation(); + const fakeMessage = getFakeMessage({ + role: 'user', + conversation_id: fakeConversation.id, + user_id: fakeConversation.user_id, + content: question + }); + + test('the send button is disabled when there is no text in the input', () => { + render(ChatPage); + const submitBtn = screen.getByLabelText('send'); + expect(submitBtn).toHaveProperty('disabled', true); + }); + + it('submits the form then clears the input without throwing errors', async () => { + mockNewConversation(); + mockChatCompletion(); + mockNewMessage(fakeMessage); + + conversationsStore.set({ + conversations: [] + }); + + const user = userEvent.setup(); + + const { getByLabelText } = render(ChatPage); + + const input = getByLabelText('message input') as HTMLInputElement; + const submitBtn = getByLabelText('send'); + + await user.type(input, question); + expect(input.value).toBe(question); + + await user.click(submitBtn); + + expect(input.value).toBe(''); + }); + + it('disables the input while a response is being processed', async () => { + const delayTime = 500; + mockNewConversation(); + mockChatCompletion({ withDelay: true, delayTime: delayTime }); + mockNewMessage(fakeMessage); + + conversationsStore.set({ + conversations: [] + }); + + const user = userEvent.setup(); + + const { getByLabelText } = render(ChatPage); + + const input = getByLabelText('message input') as HTMLInputElement; + const submitBtn = getByLabelText('send'); + + await user.type(input, question); + await user.click(submitBtn); + + // submit is disabled while waiting for AI response + expect(submitBtn).toHaveProperty('disabled', true); + + await delay(delayTime); + + await user.type(input, 'new question'); + // submit re-enabled after getting response + expect(submitBtn).toHaveProperty('disabled', false); + }); + + it('displays a toast error notification when there is an error with the AI response', async () => { + mockChatCompletionError(); + mockNewConversation(); + + const user = userEvent.setup(); + const { getByLabelText } = render(ChatPageWithToast); + + const input = getByLabelText('message input') as HTMLInputElement; + const submitBtn = getByLabelText('send'); + + await user.type(input, question); + await user.click(submitBtn); + + await screen.findAllByText('Error getting AI Response'); + }); + }); +}); diff --git a/src/leapfrogai_ui/src/schemas/chat.ts b/src/leapfrogai_ui/src/schemas/chat.ts new file mode 100644 index 000000000..11ccbd402 --- /dev/null +++ b/src/leapfrogai_ui/src/schemas/chat.ts @@ -0,0 +1,10 @@ +import { array, object, ObjectSchema, string } from 'yup'; + +export const messageSchema: ObjectSchema = object({ + content: string().required(), + role: string<'user' | 'system'>().required() +}) + .noUnknown(true) + .strict(); + +export const messagesSchema = array().of(messageSchema).strict(); diff --git a/src/leapfrogai_ui/src/styles/main.scss b/src/leapfrogai_ui/src/styles/main.scss new file mode 100644 index 000000000..9cb4769d2 --- /dev/null +++ b/src/leapfrogai_ui/src/styles/main.scss @@ -0,0 +1,10 @@ +:root { + --header-height: 3rem; + --sidebar-width: 16rem; +} + +.centered-flexbox { + display: flex; + justify-content: center; + align-items: center; +} diff --git a/src/leapfrogai_ui/src/testUtils/fakeData/index.ts b/src/leapfrogai_ui/src/testUtils/fakeData/index.ts new file mode 100644 index 000000000..d263d30d1 --- /dev/null +++ b/src/leapfrogai_ui/src/testUtils/fakeData/index.ts @@ -0,0 +1,78 @@ +import { faker } from '@faker-js/faker'; + +const todayOverride = new Date('2024-03-20T00:00'); + +const userId = faker.string.uuid(); + +export const getFakeMessage = ({ + id = faker.string.uuid(), + role = 'user', + conversation_id = faker.string.uuid(), + user_id = faker.string.uuid(), + content = faker.lorem.lines(1), + inserted_at = new Date().toISOString() +}: Partial): Message => ({ + id, + role, + user_id, + conversation_id, + content, + inserted_at +}); + +type FakeConversationOptions = { + label?: string; + numMessages?: number; + messages?: Message[]; + insertedAt?: string; +}; + +export const getFakeConversation = (options: FakeConversationOptions = {}): Conversation => { + const { + label = faker.lorem.sentence(4), + messages = [], + insertedAt = new Date().toISOString(), + numMessages = 0 + } = options; + + const conversationId = faker.string.uuid(); + + if (messages.length === 0 && numMessages > 0) { + for (let i = 0; i < numMessages; i++) { + messages.push( + getFakeMessage({ + role: i % 2 === 0 ? 'user' : 'system', + conversation_id: conversationId, + user_id: userId + }) + ); + } + } + + return { + id: conversationId, + label, + user_id: userId, + inserted_at: insertedAt, + messages: messages + }; +}; + +export const fakeConversations: Conversation[] = [ + // today + getFakeConversation({ numMessages: 2, insertedAt: todayOverride.toDateString() }), + // yesterday + getFakeConversation({ + numMessages: 2, + insertedAt: new Date( + todayOverride.getFullYear(), + todayOverride.getMonth(), + todayOverride.getDate() - 1 + ).toDateString() + }), + // This Month + getFakeConversation({ + numMessages: 2, + insertedAt: new Date(todayOverride.getFullYear(), todayOverride.getMonth(), 10).toDateString() + }) +]; diff --git a/src/leapfrogai_ui/static/favicon.png b/src/leapfrogai_ui/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..78cf0e0c279101c56390164b422372facf71aa3d GIT binary patch literal 10974 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.s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/src/leapfrogai_ui/supabase/migrations/20240322174519_create_conversations_table.sql b/src/leapfrogai_ui/supabase/migrations/20240322174519_create_conversations_table.sql new file mode 100644 index 000000000..0f6d7d9f8 --- /dev/null +++ b/src/leapfrogai_ui/supabase/migrations/20240322174519_create_conversations_table.sql @@ -0,0 +1,6 @@ +create table conversations ( + id uuid primary key DEFAULT uuid_generate_v4(), + user_id uuid references auth.users not null, + label text, + inserted_at timestamp with time zone default timezone('utc'::text, now()) not null +); \ No newline at end of file diff --git a/src/leapfrogai_ui/supabase/migrations/20240322174700_create_messages_table.sql b/src/leapfrogai_ui/supabase/migrations/20240322174700_create_messages_table.sql new file mode 100644 index 000000000..2f6559cdd --- /dev/null +++ b/src/leapfrogai_ui/supabase/migrations/20240322174700_create_messages_table.sql @@ -0,0 +1,8 @@ +create table messages ( + id uuid primary key DEFAULT uuid_generate_v4(), + user_id uuid references auth.users not null, + conversation_id uuid references conversations on delete cascade not null, + role text check (role in ('system', 'user')), + content text, + inserted_at timestamp with time zone default timezone('utc'::text, now()) not null +); \ No newline at end of file diff --git a/src/leapfrogai_ui/supabase/migrations/20240322174734_create_profiles_table.sql b/src/leapfrogai_ui/supabase/migrations/20240322174734_create_profiles_table.sql new file mode 100644 index 000000000..17861b70a --- /dev/null +++ b/src/leapfrogai_ui/supabase/migrations/20240322174734_create_profiles_table.sql @@ -0,0 +1,11 @@ +-- Create a table for public profiles +create table profiles ( + id uuid references auth.users not null primary key, + updated_at timestamp with time zone, + username text unique, + full_name text, + avatar_url text, + website text, + + constraint username_length check (char_length(username) >= 3) +); \ No newline at end of file diff --git a/src/leapfrogai_ui/supabase/migrations/20240322174754_create_role_level_security.sql b/src/leapfrogai_ui/supabase/migrations/20240322174754_create_role_level_security.sql new file mode 100644 index 000000000..8824bc3b1 --- /dev/null +++ b/src/leapfrogai_ui/supabase/migrations/20240322174754_create_role_level_security.sql @@ -0,0 +1,46 @@ +alter table conversations enable row level security; + +alter table messages enable row level security; + +alter table profiles enable row level security; + +-- Policies for conversations +create policy "Individuals can create conversations." on conversations for + insert with check (auth.uid() = user_id); +create policy "Individuals can view their own conversations. " on conversations for + select using (auth.uid() = user_id); +create policy "Individuals can update their own conversations." on conversations for + update using (auth.uid() = user_id); +create policy "Individuals can delete their own conversations." on conversations for + delete using (auth.uid() = user_id); + +-- Policies for messages +create policy "Individuals can view their own messages." on messages for + select using (auth.uid() = user_id); +create policy "Individuals can create messages." on messages for + insert with check (auth.uid() = user_id); +create policy "Individuals can update their own messages." on messages for + update using (auth.uid() = user_id); +create policy "Individuals can delete their own messages." on messages for + delete using (auth.uid() = user_id); + +-- Policies for profiles +create policy "Public profiles are viewable by everyone." on profiles + for select using (true); + +create policy "Users can insert their own profile." on profiles + for insert with check (auth.uid() = id); + +create policy "Users can update own profile." on profiles + for update using (auth.uid() = id); + +-- Set up access controls for storage. +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. +create policy "Avatar images are publicly accessible." on storage.objects + for select using (bucket_id = 'avatars'); + +create policy "Anyone can upload an avatar." on storage.objects + for insert with check (bucket_id = 'avatars'); + +create policy "Anyone can update their own avatar." on storage.objects + for update using (auth.uid() = owner) with check (bucket_id = 'avatars'); \ No newline at end of file diff --git a/src/leapfrogai_ui/supabase/migrations/20240322174913_create_function_new_user.sql b/src/leapfrogai_ui/supabase/migrations/20240322174913_create_function_new_user.sql new file mode 100644 index 000000000..b0379b3d5 --- /dev/null +++ b/src/leapfrogai_ui/supabase/migrations/20240322174913_create_function_new_user.sql @@ -0,0 +1,17 @@ +-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth. +-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details. +create function public.handle_new_user() +returns trigger as $$ +begin + insert into public.profiles (id, full_name, avatar_url) + values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url'); + return new; +end; +$$ language plpgsql security definer; +create trigger on_auth_user_created + after insert on auth.users + for each row execute procedure public.handle_new_user(); + +-- Set up Storage! +insert into storage.buckets (id, name) + values ('avatars', 'avatars'); \ No newline at end of file diff --git a/src/leapfrogai_ui/supabase/seed.sql b/src/leapfrogai_ui/supabase/seed.sql new file mode 100644 index 000000000..504011a95 --- /dev/null +++ b/src/leapfrogai_ui/supabase/seed.sql @@ -0,0 +1,116 @@ +-- create test users +INSERT INTO + auth.users ( + instance_id, + id, + aud, + role, + email, + encrypted_password, + email_confirmed_at, + recovery_sent_at, + last_sign_in_at, + raw_app_meta_data, + raw_user_meta_data, + created_at, + updated_at, + confirmation_token, + email_change, + email_change_token_new, + recovery_token + ) ( + select + '00000000-0000-0000-0000-000000000000', + uuid_generate_v4 (), + 'authenticated', + 'authenticated', + 'user' || (ROW_NUMBER() OVER ()) || '@test.com', + crypt ('password123', gen_salt ('bf')), + current_timestamp, + current_timestamp, + current_timestamp, + '{"provider":"email","providers":["email"]}', + '{}', + current_timestamp, + current_timestamp, + '', + '', + '', + '' + FROM + generate_series(1, 3) + ); + +-- test user email identities +INSERT INTO + auth.identities ( + id, + user_id, + identity_data, + provider_id, + provider, + last_sign_in_at, + created_at, + updated_at + ) ( + select + uuid_generate_v4 (), + id, + format('{"sub":"%s","email":"%s"}', id::text, email)::jsonb, + id, + 'email', + current_timestamp, + current_timestamp, + current_timestamp + from + auth.users + ); + +-- seed conversations +insert into public.conversations (user_id, label) +values( + (SELECT user_id FROM auth.identities WHERE email = 'user1@test.com'), + 'conversation 1' +); +insert into public.conversations (user_id, label) +values( + (SELECT user_id FROM auth.identities WHERE email = 'user1@test.com'), + 'conversation 2' +); + +-- seed messages +WITH user1 AS ( + SELECT user_id FROM auth.identities WHERE email = 'user1@test.com' +), conversation1 AS ( + SELECT id FROM public.conversations WHERE label = 'conversation 1' +) +INSERT INTO public.messages (user_id, conversation_id, role, content) +VALUES ( + (SELECT user_id FROM user1), + (SELECT id FROM conversation1), + 'user', + 'What is AI?' +), ( + (SELECT user_id FROM user1), + (SELECT id FROM conversation1), + 'system', + 'AI is the simulation of human intelligence processes by machines, especially computer systems.' +); + +WITH user1 AS ( + SELECT user_id FROM auth.identities WHERE email = 'user1@test.com' +), conversation2 AS ( + SELECT id FROM public.conversations WHERE label = 'conversation 2' +) +INSERT INTO public.messages (user_id, conversation_id, role, content) +VALUES ( + (SELECT user_id FROM user1), + (SELECT id FROM conversation2), + 'user', + 'What is RAG?' +), ( + (SELECT user_id FROM user1), + (SELECT id FROM conversation2), + 'system', + 'Retrieval-augmented generation (RAG) is a technique for enhancing the accuracy and reliability of generative AI models with facts fetched from external sources.' +); \ No newline at end of file diff --git a/src/leapfrogai_ui/svelte.config.js b/src/leapfrogai_ui/svelte.config.js new file mode 100644 index 000000000..af0f9655a --- /dev/null +++ b/src/leapfrogai_ui/svelte.config.js @@ -0,0 +1,25 @@ +import adapter from '@sveltejs/adapter-node'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; +import { optimizeImports } from 'carbon-preprocess-svelte'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + // Consult https://kit.svelte.dev/docs/integrations#preprocessors + // for more information about preprocessors + preprocess: [vitePreprocess(), optimizeImports()], + + kit: { + // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. + // If your environment is not supported or you settled on a specific environment, switch out the adapter. + // See https://kit.svelte.dev/docs/adapters for more information about adapters. + adapter: adapter(), + alias: { + $components: 'src/lib/components', + $stores: 'src/lib/stores', + $helpers: 'src/lib/helpers', + $assets: 'src/lib/assets' + } + } +}; + +export default config; diff --git a/src/leapfrogai_ui/tests/api.test.ts b/src/leapfrogai_ui/tests/api.test.ts new file mode 100644 index 000000000..d37527836 --- /dev/null +++ b/src/leapfrogai_ui/tests/api.test.ts @@ -0,0 +1,19 @@ +import { test, expect } from '@playwright/test'; + +test.skip('/api/chat returns a 400 when messages are incorrectly formatted', async ({ request }) => { + const messages = { + messages: [{ role: 'user', content: 'test', break: 'me' }] + }; + const res = await request.post('/api/chat', { data: messages }); + expect(res.status()).toEqual(400); +}); + +test.skip('/api/chat returns an AI response', async ({ request }) => { + const messages = { + messages: [{ role: 'user', content: 'test' }] + }; + const res = await request.post('/api/chat', { data: messages }); + const message = await res.json(); + console.log(message); + expect(message.length).toBeGreaterThan(0); +}); diff --git a/src/leapfrogai_ui/tests/auth.setup.ts b/src/leapfrogai_ui/tests/auth.setup.ts new file mode 100644 index 000000000..751048f70 --- /dev/null +++ b/src/leapfrogai_ui/tests/auth.setup.ts @@ -0,0 +1,45 @@ +import { test as setup } from '@playwright/test'; +const authFile = 'playwright/.auth/user.json'; +import * as OTPAuth from 'otpauth'; + +setup('authenticate', async ({ page }) => { + // Perform authentication steps. Replace these actions with your own. + await page.goto('http://localhost:4173'); + await page.getByRole('button', { name: 'Log In' }).click(); + await page.getByLabel('Username or email').fill(process.env.USERNAME!); + await page.getByLabel('Password').click(); + await page.getByLabel('Password').fill(process.env.PASSWORD!); + await page.getByRole('button', { name: 'Log In' }).click(); + + const totp = new OTPAuth.TOTP({ + issuer: 'Unicorn Delivery Service', + algorithm: 'SHA1', + digits: 6, + period: 30, + secret: process.env.MFA_SECRET! + }); + const code = totp.generate(); + await page.getByLabel('Six digit code').fill(code); + await page.getByRole('button', { name: 'Log In' }).click(); + + // Chrome gets stuck here for an unknown reason, does not happen in real life + // This hack allows the test to continue + // ref: https://github.com/microsoft/playwright/issues/16160 + // I suspect it is an issue with the Supbase callback, but the output in the Playwright UI does not show the error page + // I was able to see the error when using a VSCode Playwright plugin that records your actions + await page.waitForLoadState('domcontentloaded'); + await page.reload(); + + // Wait until the page receives the cookies. + // + // Login flow sets cookies in the process of several redirects. + // Wait for the final URL to ensure that the cookies are actually set. + await page.waitForURL('http://localhost:4173/chat'); + + // Alternatively, you can wait until the page reaches a state where all cookies are set. + // await expect(page.getByRole('button', { name: 'View profile and more' })).toBeVisible(); + + // End of authentication steps. + + await page.context().storageState({ path: authFile }); +}); diff --git a/src/leapfrogai_ui/tests/chat.test.ts b/src/leapfrogai_ui/tests/chat.test.ts new file mode 100644 index 000000000..f7a51da10 --- /dev/null +++ b/src/leapfrogai_ui/tests/chat.test.ts @@ -0,0 +1,54 @@ +import { faker } from '@faker-js/faker'; +import { expect, type Page, test } from '@playwright/test'; +import { deleteConversation, sendMessage } from './helpers'; + +const loadPage = async (page: Page) => { + await page.goto('/chat'); + await expect(page).toHaveTitle('LeapfrogAI - Chat'); +}; + +test('it can start a new conversation and receive a response', async ({ page }) => { + const newMessage = faker.lorem.words(3); + let messages = await page.getByTestId('message'); + await expect(messages).toHaveCount(0); + + await loadPage(page); + await sendMessage(page, newMessage); + + messages = await page.getByTestId('message'); + await expect(messages).toHaveCount(2); + + await expect(page.getByText('Internal Server Error')).toHaveCount(0); + + await deleteConversation(page, newMessage); +}); + +// Flaky test - works manually. More likely to pass in Chrome than Firefox. +test.skip('it saves in progress responses when interrupted by a page reload', async ({ page }) => { + test.use({ defaultBrowserType: 'chromium' }); // This sets the browser to Firefox for this test + + const newMessage = faker.lorem.words(20); + await loadPage(page); + const messages = page.getByTestId('message'); + await sendMessage(page, newMessage); + await expect(messages).toHaveCount(2); + + await page.reload(); + await expect(page.getByTestId('message')).toHaveCount(2); + + await deleteConversation(page, newMessage); +}); + +test('it save in progress responses when interrupted by changing threads', async ({ page }) => { + const newMessage = faker.lorem.words(3); + await loadPage(page); + const messages = page.getByTestId('message'); + await sendMessage(page, newMessage); + await expect(messages).toHaveCount(2); + + await page.getByText('New Chat').click(); + await page.getByText(newMessage).click(); // switch conversations by clicking conversation label + await expect(page.getByTestId('message')).toHaveCount(2); + + await deleteConversation(page, newMessage); +}); diff --git a/src/leapfrogai_ui/tests/helpers.ts b/src/leapfrogai_ui/tests/helpers.ts new file mode 100644 index 000000000..da5a28b46 --- /dev/null +++ b/src/leapfrogai_ui/tests/helpers.ts @@ -0,0 +1,15 @@ +import { expect, type Page } from '@playwright/test'; + +export const deleteConversation = async (page: Page, label: string) => { + await page.getByTestId(`overflow-menu-${label}`).click(); + await page.getByTestId(`overflow-menu-delete-${label}`).click(); + + await page.locator('button:text("Delete")').click(); + await expect(page.getByTestId(`overflow-menu-${label}`)).toHaveCount(0); +}; + +export const sendMessage = async (page: Page, message = 'Who are Defense Unicorns?') => { + await page.getByLabel('message input').fill(message); + // timeout is to wait for possible previous response to finish so send button is re-enabled + await page.click('button[type="submit"]', { timeout: 20000 }); +}; diff --git a/src/leapfrogai_ui/tests/logout.test.ts b/src/leapfrogai_ui/tests/logout.test.ts new file mode 100644 index 000000000..3c0bef9f2 --- /dev/null +++ b/src/leapfrogai_ui/tests/logout.test.ts @@ -0,0 +1,12 @@ +import { expect, test } from '@playwright/test'; + +test('it can log out', async ({ page }) => { + await page.goto('/chat'); + await expect(page).toHaveTitle('LeapfrogAI - Chat'); + await page.getByLabel('User').click(); + await page.getByLabel('Log Out').click(); + + await page.waitForURL('http://localhost:4173'); + + await expect(page.getByText('Log In')).toBeVisible(); +}); diff --git a/src/leapfrogai_ui/tests/sidebar.test.ts b/src/leapfrogai_ui/tests/sidebar.test.ts new file mode 100644 index 000000000..2a52b6aa9 --- /dev/null +++ b/src/leapfrogai_ui/tests/sidebar.test.ts @@ -0,0 +1,73 @@ +import { faker } from '@faker-js/faker'; +import { expect, test, type Page } from '@playwright/test'; +import { sendMessage } from './helpers'; +import { deleteConversation } from './helpers'; + +const loadPage = async (page: Page) => { + await page.goto('/chat'); + await expect(page).toHaveTitle('LeapfrogAI - Chat'); +}; + +test('it can delete conversations', async ({ page }) => { + const newMessage = faker.lorem.words(3); + await loadPage(page); + + const conversationLocator = page.getByText(newMessage); + + await sendMessage(page, newMessage); + await deleteConversation(page, newMessage); + await expect(conversationLocator).toHaveCount(0); +}); + +test('can edit conversation labels', async ({ page }) => { + const newMessage = faker.lorem.words(3); + const newLabel = faker.lorem.words(3); + + await loadPage(page); + + const messages = page.getByTestId('message'); + await sendMessage(page, newMessage); + await expect(messages).toHaveCount(2); + + const overflowMenu = page.getByTestId(`overflow-menu-${newMessage}`); + await overflowMenu.click(); + + await overflowMenu.getByText('Edit').click(); + + await page.getByLabel('edit conversation').fill(newLabel); + + await page.keyboard.down('Enter'); + + await page.reload(); + + const conversationId = page.url().split('/chat/')[1]; + + expect(page.getByTestId(`conversation-label-${conversationId}`).getByText(newLabel)); + + // Cleanup + await deleteConversation(page, newLabel); +}); + +test('Can switch conversation threads', async ({ page }) => { + const newMessage1 = faker.lorem.words(3); + const newMessage2 = faker.lorem.words(3); + const newMessage3 = faker.lorem.words(3); + await loadPage(page); + await sendMessage(page, newMessage1); + + const messages = page.getByTestId('message'); + await expect(messages).toHaveCount(2); // wait for AI response + await sendMessage(page, newMessage2); + await expect(messages).toHaveCount(4); + + await page.getByText('New Chat').click(); + await sendMessage(page, newMessage3); + await expect(messages).toHaveCount(2); + + await page.getByText(newMessage1).click(); // switch conversations by clicking conversation label + + await expect(messages).toHaveCount(4); + + await deleteConversation(page, newMessage1); + await deleteConversation(page, newMessage3); +}); diff --git a/src/leapfrogai_ui/tsconfig.json b/src/leapfrogai_ui/tsconfig.json new file mode 100644 index 000000000..8ca5000ea --- /dev/null +++ b/src/leapfrogai_ui/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler", + "types": ["vitest/globals", "@testing-library/jest-dom"] + } + // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/src/leapfrogai_ui/vite.config.ts b/src/leapfrogai_ui/vite.config.ts new file mode 100644 index 000000000..a8d1a6a26 --- /dev/null +++ b/src/leapfrogai_ui/vite.config.ts @@ -0,0 +1,20 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vitest/config'; + +export default defineConfig(() => ({ + plugins: [sveltekit()], + test: { + environment: 'jsdom', + setupFiles: ['./vitest-setup.ts'], + include: ['src/**/*.{test,spec}.{js,ts}'], + globals: true + }, + css: { + preprocessorOptions: { + scss: { + additionalData: + '@use "@carbon/themes/scss/themes" as *; @use "@carbon/themes" with ($theme: $g90); @use "@carbon/layout"; @use "@carbon/type";' + } + } + } +})); diff --git a/src/leapfrogai_ui/vitest-setup.ts b/src/leapfrogai_ui/vitest-setup.ts new file mode 100644 index 000000000..ed4e66389 --- /dev/null +++ b/src/leapfrogai_ui/vitest-setup.ts @@ -0,0 +1,99 @@ +import '@testing-library/jest-dom/vitest'; +import '@testing-library/svelte/vitest'; +import { setupServer } from 'msw/node'; +import type { Navigation, Page } from '@sveltejs/kit'; +import { faker } from '@faker-js/faker'; +import { readable, type Readable } from 'svelte/store'; +import { afterAll, afterEach, beforeAll, vi } from 'vitest'; +import * as environment from '$app/environment'; +import * as navigation from '$app/navigation'; +import * as stores from '$app/stores'; +import { fakeConversations } from './src/testUtils/fakeData'; + +// Mock SvelteKit runtime module $app/environment +vi.mock('$app/environment', (): typeof environment => ({ + browser: false, + dev: true, + building: false, + version: 'any' +})); + +// Mock SvelteKit runtime module $app/navigation +vi.mock('$app/navigation', (): typeof navigation => ({ + afterNavigate: () => {}, + beforeNavigate: () => {}, + disableScrollHandling: () => {}, + goto: () => Promise.resolve(), + invalidate: () => Promise.resolve(), + invalidateAll: () => Promise.resolve(), + preloadData: () => Promise.resolve({ type: 'loaded', status: 200, data: {} }), + preloadCode: () => Promise.resolve(), + onNavigate: () => {}, + pushState: () => {}, + replaceState: () => {} +})); + +// Mock SvelteKit runtime module $app/stores +vi.mock('$app/stores', (): typeof stores => { + const getStores: typeof stores.getStores = () => { + const navigating = readable(null); + const page = readable({ + url: new URL('http://localhost'), + params: {}, + route: { id: null }, + status: 200, + error: null, + // TODO - the profile and session types are incompletely mocked out + data: { + conversations: fakeConversations, + profile: {}, + session: { user: { id: faker.string.uuid() } } + }, + state: {}, + form: null + }); + const updated: Readable & { check(): Promise } = { + subscribe: readable(false).subscribe, + check: () => Promise.resolve(false) + }; + + return { navigating, page, updated }; + }; + + const page: typeof stores.page = { + subscribe(fn) { + return getStores().page.subscribe(fn); + } + }; + const navigating: typeof stores.navigating = { + subscribe(fn) { + return getStores().navigating.subscribe(fn); + } + }; + const updated: typeof stores.updated = { + subscribe(fn) { + return getStores().updated.subscribe(fn); + }, + check: () => Promise.resolve(false) + }; + + return { + getStores, + navigating, + page, + updated + }; +}); + +export const restHandlers = []; + +export const server = setupServer(...restHandlers); + +// Start server before all tests +beforeAll(() => server.listen({ onUnhandledRequest: 'error' })); + +// Close server after all tests +afterAll(() => server.close()); + +// Reset handlers after each test `important for test isolation` +afterEach(() => server.resetHandlers()); From 79beb3ddd733a3777a95118159cd5b557dbb0021 Mon Sep 17 00:00:00 2001 From: Andrew Risse Date: Wed, 3 Apr 2024 14:21:36 -0600 Subject: [PATCH 02/10] chore: remove streaming api test, fix ui flicker --- .../routes/chat/[[conversation_id]]/+layout.svelte | 1 - src/leapfrogai_ui/tests/api.test.ts | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+layout.svelte b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+layout.svelte index de6adbb44..d7a4794bd 100644 --- a/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+layout.svelte +++ b/src/leapfrogai_ui/src/routes/chat/[[conversation_id]]/+layout.svelte @@ -1,5 +1,4 @@