diff --git a/.env.example b/.env.example index 03b6ae69..6a85f21f 100644 --- a/.env.example +++ b/.env.example @@ -40,4 +40,14 @@ STACKABLE_COCKPIT_OIDC_CLIENT_SECRET=your-client-secret # Feature flags # STACKABLE_COCKPIT_COMPLETION_ENABLED=false # Disable SQL editor code completion (default: true) # STACKABLE_COCKPIT_STORAGE_BROWSER_ENABLED=true # Enable S3/HDFS file browser (default: false) +# STACKABLE_COCKPIT_ARCHIVE_PREVIEW_MAX_MB=100 # Max decompressed size for archive preview in megabytes (default: 100) +# STACKABLE_COCKPIT_PARQUET_PREVIEW_DISALLOWED_COMPRESSION_TYPES=gzip-no_offset # Comma-separated list of compression types to disallow from parquet data preview (default: "gzip-no_offset") +# PUBLIC_STACKABLE_COCKPIT_STORAGE_AUTO_CONNECT_TIMEOUT_MS=15000 # Auto-connect to last used storage after this many milliseconds (default: 15000) +# PUBLIC_STACKABLE_COCKPIT_STORAGE_RESTORE_TABS=true # File browser: continue where you left off — restore open tabs from the last session (default: false) +# PUBLIC_STACKABLE_COCKPIT_MAX_EDITABLE_FILE_SIZE=1048576 # Max file size (in bytes) of editable text files in the storage browser (default: 5 MiB) # PUBLIC_STACKABLE_COCKPIT_UPLOAD_CONCURRENCY=3 # Maximum number of concurrent file uploads (default: 3) +# PUBLIC_STACKABLE_COCKPIT_INFINITE_SCROLL_ENABLED=true # Enable infinite scroll in the storage browser (default: true) +# PUBLIC_STACKABLE_COCKPIT_STORAGE_CUT_COPY_ENABLED=true # Enables cut/copy/paste functionality in the storage browser (default: false) +# PUBLIC_STACKABLE_COCKPIT_STORAGE_PASTE_ENABLED=true # Enables paste functionality in the storage browser (default: false) +# PUBLIC_STACKABLE_COCKPIT_STORAGE_RENAME_ENABLED=true # Enables rename functionality in the storage browser (default: false) +# PUBLIC_STACKABLE_COCKPIT_STORAGE_MOVE_ENABLED=true # Enables move functionality in the storage browser (default: false) diff --git a/.env.test b/.env.test index c1b50cfe..766f4835 100644 --- a/.env.test +++ b/.env.test @@ -11,10 +11,21 @@ STACKABLE_COCKPIT_IMAGE_PREVIEW_BYTES=5242880 STACKABLE_COCKPIT_PDF_PREVIEW_BYTES=26214400 STACKABLE_COCKPIT_FILE_PREVIEW_ROWS=250 STACKABLE_COCKPIT_FILE_PREVIEW_COLUMNS=50 +STACKABLE_COCKPIT_PARQUET_PREVIEW_DISALLOWED_COMPRESSION_TYPES=gzip-no_offset PUBLIC_STACKABLE_COCKPIT_STORAGE_AUTO_CONNECT=true +PUBLIC_STACKABLE_COCKPIT_STORAGE_RESTORE_TABS=true PUBLIC_STACKABLE_COCKPIT_PAGE_SIZES=25,50,100 PUBLIC_STACKABLE_COCKPIT_DEFAULT_PAGE_SIZE=25 PUBLIC_STACKABLE_COCKPIT_MAX_RECENT_FILES=15 PUBLIC_STACKABLE_COCKPIT_UPLOAD_CONCURRENCY=3 +PUBLIC_STACKABLE_COCKPIT_INFINITE_SCROLL_ENABLED=true +PUBLIC_STACKABLE_COCKPIT_STORAGE_CUT_COPY_ENABLED=true +PUBLIC_STACKABLE_COCKPIT_STORAGE_PASTE_ENABLED=true +PUBLIC_STACKABLE_COCKPIT_STORAGE_RENAME_ENABLED=true +PUBLIC_STACKABLE_COCKPIT_STORAGE_MOVE_ENABLED=true GARAGE_ADMIN_URL=http://localhost:30902 GARAGE_ADMIN_TOKEN=stackable-cockpit-e2e-admin-token +BETTER_AUTH_URL=http://localhost:4173 +BETTER_AUTH_SECRET=stackable-cockpit-e2e-better-auth-secret +STORAGE_ENCRYPTION_KEY=a781775ee543107bfa97191691bb23c982dd9d9550542df27194ebc09d617dfd +PORT=4173 diff --git a/.github/workflows/pr_checks.yaml b/.github/workflows/pr_checks.yaml index f1b7216b..399cd25d 100644 --- a/.github/workflows/pr_checks.yaml +++ b/.github/workflows/pr_checks.yaml @@ -59,7 +59,7 @@ jobs: run: python -m pip install pre-commit - name: Run pre-commit - run: pre-commit run --all-files --show-diff-on-failure --color=always + run: pre-commit run --all-files --hook-stage manual --show-diff-on-failure --color=always unit-tests: name: Unit Tests @@ -85,10 +85,9 @@ jobs: - name: Run unit tests run: npm run test:unit - e2e-with-garage: - name: E2E Tests with Garage S3 + e2e-tests: + name: E2E Tests with Garage S3 and PostgreSQL runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -107,35 +106,13 @@ jobs: - name: Install Playwright browsers run: npx playwright install --with-deps chromium firefox - - name: Start Garage S3 and initialize bucket - run: | - # GitHub Actions services now support entrypoint + command, but we still - # start Garage manually here because service containers are created before - # actions/checkout runs. The upstream Garage image contains only the - # /garage binary (no /bin/sh), so the service cannot wait for the checked- - # out e2e/garage.toml to appear before it starts. - docker run -d --name garage \ - -p 3900:3900 \ - -p 3902:3902 \ - -e GARAGE_CONFIG_FILE=/workspace/dev/garage/garage.toml \ - -v "$PWD:/workspace" \ - --entrypoint /garage \ - oci.stackable.tech/stackable/dxflrs/garage:v2.3.0 \ - server --single-node - - # Wait for the S3 API to become available - for _ in $(seq 1 30); do - if curl -s http://localhost:3900 >/dev/null 2>&1; then - break - fi - sleep 1 - done - - S3_SECRET_ACCESS_KEY="e2e-test-secret-key-for-ci" \ - GARAGE_ADMIN_TOKEN='stackable-cockpit-e2e-admin-token' \ - S3_ENDPOINT='http://localhost:3900' \ - S3_CONFIG_PATH="$PWD/s3-config.json" \ - ./e2e/init-garage-s3.sh - - - name: Run E2E tests with Garage - run: npm run test:e2e:garage + - name: Run E2E tests with Garage and PostgreSQL + run: npm run test:e2e + + - name: Upload Playwright traces + if: always() + uses: actions/upload-artifact@v7 + with: + name: playwright-traces + path: e2e/test-results/ + retention-days: 7 diff --git a/.gitignore b/.gitignore index 871677f2..aa194c48 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ coverage/* # Playwright e2e/test-results e2e/.auth +.playwright/ # Paraglide src/lib/paraglide project.inlang/cache/ diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..32f8c50d --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24.13.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 239c27d2..1f71bd65 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,27 +43,45 @@ repos: - repo: local hooks: + # ── Fix variant (runs locally on commit — auto-fixes where possible) ── + - id: npm-lint-fix + name: npm lint with --fix (prettier + eslint) + language: system + entry: npm run lint:fix + stages: [pre-commit, pre-merge-commit] + pass_filenames: false + files: \.(svelte|ts|js|css|html|json|md)$ + + # ── Check-only variant (runs in CI — no auto-fix) ── - id: npm-lint - name: npm lint (prettier + eslint) + name: npm lint check only (prettier + eslint) language: system entry: npm run lint - stages: [pre-commit, pre-merge-commit] + stages: [manual] pass_filenames: false files: \.(svelte|ts|js|css|html|json|md)$ + # ── Shared hooks (same behaviour locally and in CI) ── - id: npm-check name: npm check (svelte-check) language: system entry: npm run check - stages: [pre-commit, pre-merge-commit] + stages: [pre-commit, pre-merge-commit, manual] pass_filenames: false files: \.(svelte|ts|js)$ + - id: npm-arch-test + name: npm arch test (fitness functions) + language: system + entry: npm run test:arch + stages: [pre-commit, pre-merge-commit, manual] + pass_filenames: false + - id: helm-lint name: helm lint language: system entry: helm lint deploy/helm/cockpit - stages: [pre-commit, pre-merge-commit] + stages: [pre-commit, pre-merge-commit, manual] pass_filenames: false files: ^deploy/helm/ @@ -76,6 +94,6 @@ repos: --set auth.oidc.discoveryUrl=https://stub --set auth.oidc.clientId=stub --set auth.oidc.clientSecret.secretKeyRef.name=stub > /dev/null' - stages: [pre-commit, pre-merge-commit] + stages: [pre-commit, pre-merge-commit, manual] pass_filenames: false files: ^deploy/helm/ diff --git a/.prettierignore b/.prettierignore index 6dbc7f7c..f2eaf48d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -33,3 +33,4 @@ coverage/ # Helm templates deploy/helm/ dev/garage/ +dev/postgresql/ diff --git a/AGENTS.md b/AGENTS.md index 68489856..11d551bd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -188,10 +188,10 @@ The application uses **Paraglide-JS v2** for type-safe, compiler-based internati ### Node.js Version -The required Node.js version is pinned in `.node-version`. Use `nvm` to install and activate it before running any `npm` commands — `npm` will hard-fail with engine errors otherwise (`.npmrc` sets `engine-strict=true`). +The required Node.js version is pinned in `.node-version` for CI and `.nvmrc` for NVM. Keep both files synchronised. Use `nvm` to install and activate it before running any `npm` commands — `npm` will hard-fail with engine errors otherwise (`.npmrc` sets `engine-strict=true`). ```bash -nvm install # installs the version from .node-version +nvm install # installs the version from .nvmrc nvm use # activates it in the current shell ``` @@ -224,6 +224,37 @@ pre-commit run --all-files # Run all checks: lint (prettier + eslint), type ch # markdownlint, yamllint, shellcheck, actionlint, hadolint, helm lint ``` +### Architecture Fitness Functions + +```bash +npm run test:arch # Run all architecture fitness function tests (~5 s) +npm run test:arch:report # Same, plus generate HTML dependency/metrics reports in /reports/ +``` + +Architecture tests live in `src/architecture/*.spec.ts` and use [ArchUnitTS](https://github.com/LukasNiessen/ArchUnitTS) together with plain Node.js `fs` checks. They run in CI and must remain **green at all times**. + +**Run `npm run test:arch` whenever you:** + +- Add a new file to `src/lib/server/` (verify it doesn't break client-boundary rules) +- Add a new Svelte component (PascalCase naming, no raw ``, no hardcoded colours) +- Add or remove message keys in `messages/en.json` (both locale files must stay in sync) +- Refactor the Trino sub-layer (circular-dependency rules) + +**What the fitness functions enforce:** + +| Category | What is checked | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Server / Client Boundary | `src/lib/client`, `stores`, `storage`, `editor`, `types` must not import `src/lib/server/**` | +| No Circular Dependencies | `src/lib/**` (excluding Trino, see TECH_DEBT.md) and `src/routes/**` must be cycle-free | +| Naming Conventions | Stores → `*.svelte.ts`; lib components → PascalCase `.svelte`; server files → no `.svelte.ts` extension | +| Code Size Limits | `.ts` files < 2 400 LOC; `.svelte` files < 1 100 LOC; test files < 1 000 LOC | +| UI Pattern Enforcement | No hardcoded Tailwind colours; no raw ``; no native date inputs; `` must have `alt`; no `
` (known violations listed in TECH_DEBT.md) | +| Server Logging | Server files must use pino logger, not `console.*` | +| i18n Compliance | `messages/en.json` and `messages/de.json` must have the same keys; no static `aria-label="English text"` (known violations listed in TECH_DEBT.md) | + +**Extending the fitness functions:** +When you add a new architectural rule (e.g., a new layer, a new naming convention), add a new `.spec.ts` file in `src/architecture/` following the existing patterns. Use archunit for TypeScript dependency/cycle rules and plain Node.js `fs` for content checks on Svelte files. + ### E2E Testing ```bash diff --git a/dev/lib/k8s.sh b/dev/lib/k8s.sh new file mode 100644 index 00000000..d659ebd6 --- /dev/null +++ b/dev/lib/k8s.sh @@ -0,0 +1,45 @@ +# shellcheck shell=bash +k8s::node_ip() { + local ip + ip=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}') + if [ -z "$ip" ]; then + log::error "Could not detect kind node IP." + fi + echo "$ip" +} + +k8s::wait_for_deployment() { + local name=$1 timeout=${2:-120} + kubectl wait --for=condition=available "deployment/$name" --timeout="${timeout}s" +} + +k8s::wait_for_statefulset() { + local name=$1 timeout=${2:-300} + kubectl rollout status "statefulset/$name" --timeout="${timeout}s" +} + +k8s::wait_for_pod() { + local label=$1 timeout=${2:-60} + kubectl wait --for=condition=ready pod -l "$label" --timeout="${timeout}s" +} + +k8s::get_pod_name() { + local label=$1 + kubectl get pod -l "$label" -o jsonpath='{.items[0].metadata.name}' +} + +k8s::get_node_port() { + local service=$1 + kubectl get svc "$service" -o jsonpath='{.spec.ports[0].nodePort}' +} + +k8s::template_and_apply() { + local file=$1 + shift + local sed_exprs=() + for pair in "$@"; do + local key="${pair%%=*}" val="${pair#*=}" + sed_exprs+=(-e "s/\${${key}}/${val}/g") + done + sed "${sed_exprs[@]}" "$file" | kubectl apply -f - +} diff --git a/dev/lib/logging.sh b/dev/lib/logging.sh new file mode 100644 index 00000000..69627eb6 --- /dev/null +++ b/dev/lib/logging.sh @@ -0,0 +1,17 @@ +# shellcheck shell=bash +log::info() { + echo " [INFO] $*" +} + +log::warn() { + echo " [WARN] $*" >&2 +} + +log::error() { + echo " [ERROR] $*" >&2 + exit 1 +} + +log::ok() { + echo " [OK] $*" +} diff --git a/dev/lib/probe.sh b/dev/lib/probe.sh new file mode 100644 index 00000000..48679416 --- /dev/null +++ b/dev/lib/probe.sh @@ -0,0 +1,25 @@ +# shellcheck shell=bash +probe::url() { + local port=$1 path=$2 + local scheme=${3:-http} + local timeout=${4:-120} + shift 4 + + local deadline url candidate + deadline=$(( $(date +%s) + timeout )) + url="" + while [ -z "$url" ] && [ "$(date +%s)" -lt "$deadline" ]; do + for candidate in "${scheme}://${NODE_IP}:${port}" "${scheme}://127.0.0.1:${port}" "${scheme}://localhost:${port}"; do + if curl -sf --max-time 2 "$@" "${candidate}${path}" >/dev/null 2>&1; then + url="$candidate" + break + fi + done + [ -z "$url" ] && sleep 2 + done + + if [ -z "$url" ]; then + return 1 + fi + echo "$url" +} diff --git a/dev/modules/env.sh b/dev/modules/env.sh new file mode 100644 index 00000000..28f22f8e --- /dev/null +++ b/dev/modules/env.sh @@ -0,0 +1,90 @@ +# shellcheck shell=bash +env::write() { + log::info "Writing .env.development..." + + local session_secret encryption_key + session_secret=$(openssl rand -hex 32) + encryption_key=$(openssl rand -hex 32) + + if [ -f "$ENV_FILE" ]; then + log::info "Backing up existing .env.development to .env.development.bak" + cp "$ENV_FILE" "$ENV_FILE.bak" + fi + + if [[ "$SKIP_TRINO" == false ]]; then + cat > "$ENV_FILE" < "$ENV_FILE" </dev/null 2>&1; do + sleep 2 + done + + kcadm() { + kubectl exec "$pod" -- /opt/keycloak/bin/kcadm.sh "$@" + } + + if kcadm get realms/stackable --fields realm 2>/dev/null | grep -q '"stackable"'; then + log::info "Realm 'stackable' already exists, skipping Keycloak configuration." + local client_uuid + client_uuid=$(kcadm get clients -r stackable --fields id,clientId \ + | grep -B1 '"stackable-cockpit"' | grep '"id"' | sed 's/.*: *"\(.*\)".*/\1/') + local client_secret + client_secret=$(kcadm get clients/"$client_uuid"/client-secret -r stackable --fields value \ + | grep '"value"' | sed 's/.*: *"\(.*\)".*/\1/') + export OIDC_CLIENT_SECRET="$client_secret" + return + fi + + log::info "Logging into Keycloak admin CLI..." + kcadm config credentials \ + --server http://localhost:8080 \ + --realm master \ + --user admin \ + --password admin + + log::info "Creating realm 'stackable'..." + kcadm create realms -s realm=stackable -s enabled=true + + log::info "Creating client 'stackable-cockpit'..." + local client_uuid + client_uuid=$(kcadm create clients -r stackable \ + -s clientId=stackable-cockpit \ + -s enabled=true \ + -s protocol=openid-connect \ + -s publicClient=false \ + -s standardFlowEnabled=true \ + -s directAccessGrantsEnabled=false \ + -s 'redirectUris=["*"]' \ + -s 'webOrigins=["*"]' \ + -i) + + log::info "Creating client 'trino'..." + kcadm create clients -r stackable \ + -s clientId=trino \ + -s enabled=true \ + -s protocol=openid-connect \ + -s publicClient=false \ + -s standardFlowEnabled=true \ + -s directAccessGrantsEnabled=false \ + -s secret=trino-oidc-dev \ + -s 'redirectUris=["*"]' \ + -s 'webOrigins=["*"]' + + __keycloak_create_user alice alicealice Alice Example + __keycloak_create_user bob bobbob Bob Example + + log::info "Fetching client secret..." + local client_secret + client_secret=$(kcadm get clients/"$client_uuid"/client-secret -r stackable --fields value \ + | grep '"value"' | sed 's/.*: *"\(.*\)".*/\1/') + export OIDC_CLIENT_SECRET="$client_secret" +} + +__keycloak_create_user() { + local username=$1 password=$2 first=$3 last=$4 + log::info "Creating user '$username'..." + kcadm create users -r stackable \ + -s username="$username" \ + -s email="$username@example.com" \ + -s firstName="$first" \ + -s lastName="$last" \ + -s enabled=true + kcadm set-password -r stackable --username "$username" --new-password "$password" +} diff --git a/dev/modules/postgresql.sh b/dev/modules/postgresql.sh new file mode 100644 index 00000000..be80b1ef --- /dev/null +++ b/dev/modules/postgresql.sh @@ -0,0 +1,28 @@ +# shellcheck shell=bash +postgresql::deploy() { + [[ "$SKIP_POSTGRESQL" == true ]] && return 0 + + log::info "Deploying PostgreSQL 18..." + helm upgrade --install postgresql "$SCRIPT_DIR/postgresql" \ + --namespace default \ + --wait \ + --timeout 60s +} + +postgresql::migrate() { + [[ "$SKIP_POSTGRESQL" == true ]] && return 0 + + log::info "Waiting for PostgreSQL to be ready..." + k8s::wait_for_pod app=postgresql 60 + + log::info "Running database migrations..." + ( + cd "$PROJECT_DIR" && + DATABASE_HOST=localhost \ + DATABASE_PORT=31432 \ + DATABASE_NAME=cockpit \ + DATABASE_USER=cockpit \ + DATABASE_PASSWORD=cockpit-dev-password \ + npx tsx src/lib/server/migrate.ts + ) +} diff --git a/dev/modules/prerequisites.sh b/dev/modules/prerequisites.sh new file mode 100644 index 00000000..a6a73053 --- /dev/null +++ b/dev/modules/prerequisites.sh @@ -0,0 +1,17 @@ +# shellcheck shell=bash +prerequisites::run() { + if [ ! -d "$PROJECT_DIR/node_modules" ]; then + log::info "Installing npm dependencies..." + (cd "$PROJECT_DIR" && npm install) + else + log::info "npm dependencies already installed, skipping." + fi + + if [[ "$SKIP_TRINO" == true ]]; then + log::info "Installing Stackable operators (commons, listener, secret)..." + stackablectl operator install commons listener secret + else + log::info "Installing Stackable operators (commons, listener, secret, trino)..." + stackablectl operator install commons listener secret trino + fi +} diff --git a/dev/modules/secret.sh b/dev/modules/secret.sh new file mode 100644 index 00000000..714fa6af --- /dev/null +++ b/dev/modules/secret.sh @@ -0,0 +1,8 @@ +# shellcheck shell=bash +secret::create() { + log::info "Creating stackable-cockpit-credentials Secret..." + kubectl delete secret stackable-cockpit-credentials --ignore-not-found + kubectl create secret generic stackable-cockpit-credentials \ + --from-literal=oidc-client-secret="$OIDC_CLIENT_SECRET" \ + --from-literal=trino-auth-password=stackable-cockpit-dev +} diff --git a/dev/modules/summary.sh b/dev/modules/summary.sh new file mode 100644 index 00000000..8c64364a --- /dev/null +++ b/dev/modules/summary.sh @@ -0,0 +1,36 @@ +# shellcheck shell=bash +summary::print() { + echo "" + log::ok "Setup complete" + echo "" + echo "Start the dev server with: npm run dev" + echo "" + echo "Keycloak: http://${NODE_IP}:30080" + echo " Admin: admin / admin" + echo "" + if [[ "$SKIP_TRINO" == false ]]; then + echo "Trino endpoint: https://${NODE_IP}:${TRINO_PORT}" + echo "" + echo "Trino connection is pre-configured via STACKABLE_COCKPIT_TRINO_* env vars." + echo "" + else + echo "Trino was skipped. Add STACKABLE_COCKPIT_TRINO_* vars to $ENV_FILE manually when ready." + echo "" + fi + if [[ "$SKIP_GARAGE" == false ]]; then + echo "Garage S3: http://${NODE_IP}:30900 (admin: http://${NODE_IP}:30902)" + echo " Credentials written to s3-config.json for E2E tests." + echo "" + fi + if [[ "$SKIP_POSTGRESQL" == false ]]; then + echo "PostgreSQL: localhost:31432" + echo " Database: cockpit" + echo " User: cockpit" + echo " Password: cockpit-dev-password" + echo " Environment: DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD" + echo "" + fi + echo "Test users (OIDC):" + echo " alice / alicealice" + echo " bob / bobbob" +} diff --git a/dev/modules/trino.sh b/dev/modules/trino.sh new file mode 100644 index 00000000..03ff0f2a --- /dev/null +++ b/dev/modules/trino.sh @@ -0,0 +1,25 @@ +# shellcheck shell=bash +trino::deploy() { + [[ "$SKIP_TRINO" == true ]] && return 0 + + log::info "Deploying Trino..." + k8s::template_and_apply "$SCRIPT_DIR/trino.yaml" "NODE_IP=$NODE_IP" +} + +trino::probe() { + [[ "$SKIP_TRINO" == true ]] && return 0 + + TRINO_PORT=$(k8s::get_node_port trino-coordinator) + + local trino_url + trino_url=$(probe::url "$TRINO_PORT" /v1/info https 30 -sk || true) + export TRINO_BASE_URL="${trino_url:-https://${NODE_IP}:${TRINO_PORT}}" +} + +trino::wait_for_ready() { + [[ "$SKIP_TRINO" == true ]] && return 0 + + log::info "Waiting for Trino to be ready..." + k8s::wait_for_statefulset trino-coordinator-default 300 + log::info "Trino endpoint: https://${NODE_IP}:${TRINO_PORT}" +} diff --git a/dev/postgresql/Chart.yaml b/dev/postgresql/Chart.yaml new file mode 100644 index 00000000..156e12f1 --- /dev/null +++ b/dev/postgresql/Chart.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v2 +name: postgresql +description: PostgreSQL 18 database for local dev and E2E testing +type: application +version: 0.1.0 +appVersion: '18' diff --git a/dev/postgresql/templates/configmap.yaml b/dev/postgresql/templates/configmap.yaml new file mode 100644 index 00000000..ef868f04 --- /dev/null +++ b/dev/postgresql/templates/configmap.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgresql-config + namespace: default +data: + postgresql.conf: |- + # PostgreSQL configuration for development + listen_addresses = '*' + max_connections = 100 + shared_buffers = 128MB + effective_cache_size = 256MB + work_mem = 4MB + pg_hba.conf: |- + # PostgreSQL Host-based Authentication + local all all trust + host all all 127.0.0.1/32 md5 + host all all ::1/128 md5 + host all all 0.0.0.0/0 md5 diff --git a/dev/postgresql/templates/deployment.yaml b/dev/postgresql/templates/deployment.yaml new file mode 100644 index 00000000..35f2729f --- /dev/null +++ b/dev/postgresql/templates/deployment.yaml @@ -0,0 +1,64 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgresql + namespace: default + labels: + app: postgresql +spec: + replicas: 1 + selector: + matchLabels: + app: postgresql + template: + metadata: + labels: + app: postgresql + spec: + containers: + - name: postgresql + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: postgres + containerPort: 5432 + protocol: TCP + env: + - name: POSTGRES_DB + value: {{ .Values.database.name | quote }} + - name: POSTGRES_USER + value: {{ .Values.database.user | quote }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: postgresql-secret + key: password + volumeMounts: + - name: data + mountPath: /var/lib/postgresql + - name: config + mountPath: /etc/postgresql + readOnly: true + readinessProbe: + exec: + command: + - /bin/sh + - -c + - pg_isready -U {{ .Values.database.user }} + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 10 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumes: + - name: data + emptyDir: {} + - name: config + configMap: + name: postgresql-config diff --git a/dev/postgresql/templates/secret.yaml b/dev/postgresql/templates/secret.yaml new file mode 100644 index 00000000..0e9bddc5 --- /dev/null +++ b/dev/postgresql/templates/secret.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: postgresql-secret + namespace: default +type: Opaque +data: + password: {{ .Values.database.password | b64enc | quote }} diff --git a/dev/postgresql/templates/service.yaml b/dev/postgresql/templates/service.yaml new file mode 100644 index 00000000..a2f4a6ea --- /dev/null +++ b/dev/postgresql/templates/service.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: postgresql + namespace: default +spec: + type: NodePort + selector: + app: postgresql + ports: + - name: postgres + port: 5432 + targetPort: 5432 + nodePort: {{ .Values.nodePorts.postgres }} diff --git a/dev/postgresql/values.yaml b/dev/postgresql/values.yaml new file mode 100644 index 00000000..241ccf70 --- /dev/null +++ b/dev/postgresql/values.yaml @@ -0,0 +1,16 @@ +--- +image: + repository: oci.stackable.tech/stackable/library/postgres + tag: '18.4-alpine3.24' + pullPolicy: IfNotPresent + +# Database configuration +database: + name: cockpit + user: cockpit + password: cockpit-dev-password + +# NodePort value for host access. +# PostgreSQL is exposed on nodePorts.postgres +nodePorts: + postgres: 31432 diff --git a/dev/setup.sh b/dev/setup.sh index 96ac2a1f..4f1897e5 100755 --- a/dev/setup.sh +++ b/dev/setup.sh @@ -3,356 +3,70 @@ # Assumes: kind cluster is running, kubectl context points to it. set -euo pipefail -SKIP_TRINO=false -SKIP_GARAGE=false +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +ENV_FILE="$PROJECT_DIR/.env.development" +export ENV_FILE + +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/lib/logging.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/lib/k8s.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/lib/probe.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/modules/prerequisites.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/modules/keycloak.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/modules/trino.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/modules/garage.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/modules/postgresql.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/modules/env.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/modules/secret.sh" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/modules/summary.sh" + +SKIP_TRINO=false; SKIP_GARAGE=false; SKIP_POSTGRESQL=false for arg in "$@"; do case "$arg" in --skip-trino) SKIP_TRINO=true ;; --skip-garage) SKIP_GARAGE=true ;; - *) echo "Unknown argument: $arg"; echo "Usage: $0 [--skip-trino] [--skip-garage]"; exit 1 ;; + --skip-postgresql) SKIP_POSTGRESQL=true ;; + *) echo "Unknown argument: $arg"; echo "Usage: $0 [--skip-trino] [--skip-garage] [--skip-postgresql]"; exit 1 ;; esac done +export SKIP_TRINO SKIP_GARAGE SKIP_POSTGRESQL -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -ENV_FILE="$PROJECT_DIR/.env.development" - -echo "=== Stackable Cockpit dev environment setup ===" -if [[ "$SKIP_TRINO" == true ]]; then - echo "(Trino deployment skipped via --skip-trino)" -fi -if [[ "$SKIP_GARAGE" == true ]]; then - echo "(Garage deployment skipped via --skip-garage)" -fi -echo "" - -# ------------------------------------------------------------------ -# 1. Install npm dependencies if needed -# ------------------------------------------------------------------ -if [ ! -d "$PROJECT_DIR/node_modules" ]; then - echo "Installing npm dependencies..." - (cd "$PROJECT_DIR" && npm install) -else - echo "npm dependencies already installed, skipping." -fi - -# ------------------------------------------------------------------ -# 2. Install Stackable operators -# ------------------------------------------------------------------ -echo "" -if [[ "$SKIP_TRINO" == true ]]; then - echo "Installing Stackable operators (commons, listener, secret)..." - stackablectl operator install commons listener secret -else - echo "Installing Stackable operators (commons, listener, secret, trino)..." - stackablectl operator install commons listener secret trino -fi - -# ------------------------------------------------------------------ -# 3. Deploy Keycloak -# ------------------------------------------------------------------ -echo "" -echo "Deploying Keycloak..." -kubectl apply -f "$SCRIPT_DIR/keycloak.yaml" - -# ------------------------------------------------------------------ -# 4. Wait for Keycloak and configure realm/client/users -# ------------------------------------------------------------------ +log::info "Stackable Cockpit dev environment setup" +[[ "$SKIP_TRINO" == true ]] && echo " (Trino deployment skipped)" +[[ "$SKIP_GARAGE" == true ]] && echo " (Garage deployment skipped)" +[[ "$SKIP_POSTGRESQL" == true ]] && echo " (PostgreSQL deployment skipped)" echo "" -echo "Waiting for Keycloak deployment to be available..." -kubectl wait --for=condition=available deployment/keycloak --timeout=120s - -POD=$(kubectl get pod -l app=keycloak -o jsonpath='{.items[0].metadata.name}') -NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}') -if [ -z "$NODE_IP" ]; then - echo "ERROR: Could not detect kind node IP." - exit 1 -fi -echo "Node IP: $NODE_IP" - -# ------------------------------------------------------------------ -# 5. Deploy Trino (after node IP is known, trino.yaml is a template) -# ------------------------------------------------------------------ -if [[ "$SKIP_TRINO" == false ]]; then - echo "" - echo "Deploying Trino..." - sed "s/\${NODE_IP}/$NODE_IP/g" "$SCRIPT_DIR/trino.yaml" | kubectl apply -f - -fi - -# ------------------------------------------------------------------ -# 5b. Deploy Garage S3 (via Helm) -# ------------------------------------------------------------------ -if [[ "$SKIP_GARAGE" == false ]]; then - echo "" - echo "Deploying Garage S3..." - helm upgrade --install garage "$SCRIPT_DIR/garage" \ - --namespace default \ - --wait \ - --timeout 60s -fi - -# On some local Kubernetes distributions (e.g. Rancher Desktop k3s), the node's -# InternalIP is not reachable from the host network, but NodePorts are exposed -# on localhost. Probe both and use the first reachable URL. -KEYCLOAK_BASE_URL="" -deadline=$(( $(date +%s) + 120 )) -while [ -z "$KEYCLOAK_BASE_URL" ] && [ "$(date +%s)" -lt "$deadline" ]; do - for base in "http://${NODE_IP}:30080" "http://127.0.0.1:30080" "http://localhost:30080"; do - if curl -sf --max-time 2 "${base}/realms/master" >/dev/null 2>&1; then - KEYCLOAK_BASE_URL="$base" - break - fi - done - [ -z "$KEYCLOAK_BASE_URL" ] && sleep 2 -done - -if [ -z "$KEYCLOAK_BASE_URL" ]; then - echo "ERROR: Could not reach Keycloak via NodePort 30080 within 120s." - echo "Tried: http://${NODE_IP}:30080, http://127.0.0.1:30080, http://localhost:30080" - exit 1 -fi -echo "Keycloak URL: ${KEYCLOAK_BASE_URL}" - -echo "Waiting for Keycloak to accept connections" -until curl -sf "${KEYCLOAK_BASE_URL}/realms/master" >/dev/null 2>&1; do - sleep 2 -done - -kcadm() { - kubectl exec "$POD" -- /opt/keycloak/bin/kcadm.sh "$@" -} - -# Check if realm already exists -if kcadm get realms/stackable --fields realm 2>/dev/null | grep -q '"stackable"'; then - echo "Realm 'stackable' already exists, skipping Keycloak configuration." - # Still need to fetch the client secret - CLIENT_UUID=$(kcadm get clients -r stackable --fields id,clientId \ - | grep -B1 '"stackable-cockpit"' | grep '"id"' | sed 's/.*: *"\(.*\)".*/\1/') - SECRET=$(kcadm get clients/"$CLIENT_UUID"/client-secret -r stackable --fields value \ - | grep '"value"' | sed 's/.*: *"\(.*\)".*/\1/') -else - echo "Logging into Keycloak admin CLI..." - kcadm config credentials \ - --server http://localhost:8080 \ - --realm master \ - --user admin \ - --password admin - - echo "Creating realm 'stackable'..." - kcadm create realms \ - -s realm=stackable \ - -s enabled=true - - echo "Creating client 'stackable-cockpit'..." - CLIENT_UUID=$(kcadm create clients \ - -r stackable \ - -s clientId=stackable-cockpit \ - -s enabled=true \ - -s protocol=openid-connect \ - -s publicClient=false \ - -s standardFlowEnabled=true \ - -s directAccessGrantsEnabled=false \ - -s 'redirectUris=["*"]' \ - -s 'webOrigins=["*"]' \ - -i) - echo "Creating client 'trino'..." - kcadm create clients \ - -r stackable \ - -s clientId=trino \ - -s enabled=true \ - -s protocol=openid-connect \ - -s publicClient=false \ - -s standardFlowEnabled=true \ - -s directAccessGrantsEnabled=false \ - -s secret=trino-oidc-dev \ - -s 'redirectUris=["*"]' \ - -s 'webOrigins=["*"]' - - create_user() { - local username=$1 password=$2 first=$3 last=$4 - echo "Creating user '$username'..." - kcadm create users \ - -r stackable \ - -s username="$username" \ - -s email="$username@example.com" \ - -s firstName="$first" \ - -s lastName="$last" \ - -s enabled=true - kcadm set-password \ - -r stackable \ - --username "$username" \ - --new-password "$password" - } - - create_user alice alicealice Alice Example - create_user bob bobbob Bob Example - - echo "Fetching client secret..." - SECRET=$(kcadm get clients/"$CLIENT_UUID"/client-secret -r stackable --fields value \ - | grep '"value"' | sed 's/.*: *"\(.*\)".*/\1/') -fi - -# ------------------------------------------------------------------ -# 7. Initialise Garage S3 (create bucket + access key, write s3-config.json) -# ------------------------------------------------------------------ -if [[ "$SKIP_GARAGE" == false ]]; then - echo "" - echo "Initialising Garage S3..." - - GARAGE_ADMIN_PORT=30902 - GARAGE_S3_PORT=30900 - GARAGE_BASE_URL="" - deadline=$(( $(date +%s) + 60 )) - while [ -z "$GARAGE_BASE_URL" ] && [ "$(date +%s)" -lt "$deadline" ]; do - for base in "http://${NODE_IP}:${GARAGE_ADMIN_PORT}" "http://127.0.0.1:${GARAGE_ADMIN_PORT}" "http://localhost:${GARAGE_ADMIN_PORT}"; do - if curl -sf --max-time 2 -H "Authorization: Bearer stackable-cockpit-e2e-admin-token" "${base}/v2/ListBuckets" >/dev/null 2>&1; then - GARAGE_BASE_URL="$base" - break - fi - done - [ -z "$GARAGE_BASE_URL" ] && sleep 2 - done - - if [ -z "$GARAGE_BASE_URL" ]; then - echo "ERROR: Could not reach Garage admin API via NodePort ${GARAGE_ADMIN_PORT} within 60s." - echo "Tried: http://${NODE_IP}:${GARAGE_ADMIN_PORT}, http://127.0.0.1:${GARAGE_ADMIN_PORT}, http://localhost:${GARAGE_ADMIN_PORT}" - exit 1 - fi - - # Derive the matching S3 base URL from the same host - GARAGE_HOST=$(echo "$GARAGE_BASE_URL" | sed 's|http://||; s|:[0-9]*$||') - GARAGE_S3_URL="http://${GARAGE_HOST}:${GARAGE_S3_PORT}" - - S3_SECRET_ACCESS_KEY=$(openssl rand -hex 32) \ - GARAGE_ADMIN_TOKEN=stackable-cockpit-e2e-admin-token \ - S3_ENDPOINT="$GARAGE_S3_URL" \ - GARAGE_ADMIN_URL="$GARAGE_BASE_URL" \ - S3_CONFIG_PATH="$PROJECT_DIR/s3-config.json" \ - "$SCRIPT_DIR/../e2e/init-garage-s3.sh" - - echo "Wrote s3-config.json (S3 endpoint: ${GARAGE_S3_URL})" -fi - -# ------------------------------------------------------------------ -# 8. Write .env.development -# ------------------------------------------------------------------ -echo "" -SESSION_SECRET=$(openssl rand -hex 32) - -if [ -f "$ENV_FILE" ]; then - echo "Backing up existing .env.development to .env.development.bak" - cp "$ENV_FILE" "$ENV_FILE.bak" -fi - -if [[ "$SKIP_TRINO" == false ]]; then - TRINO_PORT=$(kubectl get svc trino-coordinator -o jsonpath='{.spec.ports[0].nodePort}') - - # Probe Trino reachability the same way we did for Keycloak. - TRINO_BASE_URL="" - for base in "https://${NODE_IP}:${TRINO_PORT}" "https://127.0.0.1:${TRINO_PORT}" "https://localhost:${TRINO_PORT}"; do - if curl -sfk --max-time 2 "${base}/v1/info" >/dev/null 2>&1; then - TRINO_BASE_URL="$base" - break - fi - done - # Fall back to NODE_IP if none respond yet (Trino may still be starting). - TRINO_BASE_URL="${TRINO_BASE_URL:-https://${NODE_IP}:${TRINO_PORT}}" -fi - -if [[ "$SKIP_TRINO" == false ]]; then - cat > "$ENV_FILE" < "$ENV_FILE" < { + const log = locals.logger; + + try { + // Query example + const users = await db.query.users.findMany(); + log.info({ count: users.length }, 'Loaded users'); + return { users }; + } catch (error) { + log.error({ error }, 'Database query failed'); + throw error; + } +}; +``` + +### Connection Testing + +The database connection is tested automatically when the server starts. Check the logs for connection status: + +```bash +npm run dev # Check terminal output for "Database connection successful" +``` + +## Documentation + +- [Drizzle ORM Docs](https://orm.drizzle.team/docs/overview) +- [PostgreSQL Driver](https://orm.drizzle.team/docs/get-started-postgresql) +- [Query API](https://orm.drizzle.team/docs/select) + +## Troubleshooting + +### Connection Failed + +1. Ensure PostgreSQL is running: `kubectl get pod -l app=postgresql` +2. Check environment variables: `env | grep DATABASE_` +3. Verify the database exists: `psql -h localhost -U cockpit -d cockpit` +4. Check logs: `kubectl logs -l app=postgresql` + +### Schema Sync Issues + +If schema changes aren't reflected: + +```bash +npm run db:generate # Regenerate migrations +npm run db:migrate # Apply migrations +npm run dev # Restart dev server +``` + +### View Database State + +To inspect the current database state: + +```bash +npm run db:studio # Opens Drizzle Studio for visual inspection +``` + +Or use psql directly: + +```bash +psql -h localhost -U cockpit -d cockpit +# Once connected: +\dt # List all tables +\d # Describe a table +SELECT * FROM ; # View data +``` + +## Security + +### SSL/TLS Configuration + +- **Development** (`NODE_ENV != production`): SSL is **disabled** by default for local Kubernetes +- **Production** (`NODE_ENV = production`): SSL is **always enabled** for security + +This is configured automatically in both: + +- `drizzle.config.ts` - for migrations and Drizzle Studio +- `src/lib/server/db.ts` - for the application runtime + +**Never disable SSL in production.** Unencrypted database connections expose credentials and data to network attacks. diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 00000000..522aab1f --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'drizzle-kit'; + +const isDev = process.env.NODE_ENV !== 'production'; + +export default defineConfig({ + schema: ['./src/lib/server/schema.ts', './src/lib/server/auth-schema.ts'], + out: './src/lib/server/migrations', + dialect: 'postgresql', + dbCredentials: { + host: process.env.DATABASE_HOST ?? 'localhost', + port: Number(process.env.DATABASE_PORT ?? 31432), + database: process.env.DATABASE_NAME ?? 'cockpit', + user: process.env.DATABASE_USER ?? 'cockpit', + password: process.env.DATABASE_PASSWORD ?? 'cockpit-dev-password', + ssl: !isDev + } +}); diff --git a/e2e/database/db.spec.ts b/e2e/database/db.spec.ts new file mode 100644 index 00000000..8b9b287a --- /dev/null +++ b/e2e/database/db.spec.ts @@ -0,0 +1,24 @@ +import { test, expect } from '@playwright/test'; +import { Client } from 'pg'; + +test.describe('Database connectivity', () => { + test('connects to the database and reports the database as healthy', async () => { + const client = new Client({ + host: process.env.DATABASE_HOST, + port: parseInt(process.env.DATABASE_PORT ?? '5432', 10), + database: process.env.DATABASE_NAME, + user: process.env.DATABASE_USER, + password: process.env.DATABASE_PASSWORD, + ssl: false + }); + + await client.connect(); + try { + await client.query('SELECT 1 FROM user_storage_connections LIMIT 0'); + } finally { + await client.end(); + } + + expect(true).toBe(true); + }); +}); diff --git a/e2e/i18n.spec.ts b/e2e/i18n.spec.ts index 73b9ce29..559c777b 100644 --- a/e2e/i18n.spec.ts +++ b/e2e/i18n.spec.ts @@ -6,6 +6,7 @@ import { waitForHydration } from './support/helpers'; /** Load the saved auth storage state, optionally stripping the locale cookie. */ function loadAuthState(projectName: string, { withoutLocale = false } = {}) { const authFile = path.join(import.meta.dirname, `.auth/user-setup-${projectName}.json`); + // eslint-disable-next-line security/detect-non-literal-fs-filename const state = JSON.parse(fs.readFileSync(authFile, 'utf-8')); if (withoutLocale) { state.cookies = state.cookies.filter((c: { name: string }) => c.name !== 'PARAGLIDE_LOCALE'); @@ -16,9 +17,18 @@ function loadAuthState(projectName: string, { withoutLocale = false } = {}) { test.describe('Internationalisation', () => { test.use({ locale: 'en-US' }); + // Firefox is slower to hydrate and navigate; triple the default timeout for + // all tests in this block so they don't time out on slow CI runners. + test.beforeEach(() => { + test.slow(); + }); + test('renders in English by default with lang="en"', async ({ page }) => { await page.goto('/'); + // Wait for hydration so reactive state has settled before checking content. + await waitForHydration(page); + const html = page.locator('html'); await expect(html).toHaveAttribute('lang', 'en'); diff --git a/e2e/init-garage-s3.sh b/e2e/init-garage-s3.sh index fd5ac81a..10c7105c 100755 --- a/e2e/init-garage-s3.sh +++ b/e2e/init-garage-s3.sh @@ -43,6 +43,22 @@ json_find_bucket_id_by_alias() { ' "$bucket_name" } +json_read_field_from_file() { + local file="$1" + local field="$2" + + node -e ' + const fs = require("fs"); + try { + const data = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); + const value = process.argv[2].split(".").reduce((current, key) => current?.[key], data); + if (value !== undefined && value !== null) { + process.stdout.write(String(value)); + } + } catch { /* file missing or invalid JSON — emit nothing */ } + ' "$file" "$field" +} + admin_post() { local path="$1" local payload="$2" @@ -75,6 +91,19 @@ create_bucket() { admin_post '/v2/CreateBucket' "{\"globalAlias\":\"$bucket_name\"}" } +# Creates a bucket with no global alias so it does not appear in S3 ListBuckets. +create_hidden_bucket() { + admin_post '/v2/CreateBucket' '{}' +} + +bucket_exists() { + local bucket_id="$1" + + curl -fsS \ + -H "Authorization: Bearer $GARAGE_ADMIN_TOKEN" \ + "$GARAGE_ADMIN_URL/v2/GetBucketInfo?id=$bucket_id" >/dev/null 2>&1 +} + allow_bucket_key() { local bucket_id="$1" local access_key_id="$2" @@ -93,6 +122,109 @@ fi allow_bucket_key "$bucket_id" "$S3_ACCESS_KEY_ID" >/dev/null +# Hidden bucket: no global alias so it is absent from S3 ListBuckets responses, +# but the access key retains read and write (not owner) access. +# Idempotent: reuse the bucket ID stored in an existing config file if the +# bucket is still present in Garage; otherwise create a new one. +hidden_bucket_id=$(json_read_field_from_file "$S3_CONFIG_PATH" 'hiddenBucketId') +if [[ -z "$hidden_bucket_id" ]] || ! bucket_exists "$hidden_bucket_id"; then + hidden_bucket_response=$(create_hidden_bucket) + hidden_bucket_id=$(printf '%s' "$hidden_bucket_response" | json_get 'id') +fi + +admin_post '/v2/AllowBucketKey' \ + "{\"bucketId\":\"$hidden_bucket_id\",\"accessKeyId\":\"$S3_ACCESS_KEY_ID\",\"permissions\":{\"owner\":false,\"read\":true,\"write\":true}}" >/dev/null +# ────────────────────────────────────────────── +# Bucket enrichment: tags, lifecycle rules, sample data +# ────────────────────────────────────────────── +echo "Enriching bucket with tags, lifecycle rules, and sample objects..." + +# Export S3 env vars so the Node.js process can read them +export S3_ENDPOINT S3_REGION S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY S3_BUCKET + +node -e ' +const { + S3Client, + PutBucketLifecycleConfigurationCommand, + PutObjectCommand +} = require("@aws-sdk/client-s3"); + +const client = new S3Client({ + endpoint: process.env.S3_ENDPOINT, + region: process.env.S3_REGION || "garage", + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + forcePathStyle: true, +}); + +const bucket = process.env.S3_BUCKET; + +async function enrich() { + // Lifecycle rules (Garage supports a subset of the S3 lifecycle API) + // Note: Garage does not implement PutBucketTagging (returns 501 Not Implemented). + try { + await client.send(new PutBucketLifecycleConfigurationCommand({ + Bucket: bucket, + LifecycleConfiguration: { + Rules: [ + { + ID: "expire-old-logs", + Status: "Enabled", + Filter: { Prefix: "logs/" }, + Expiration: { Days: 90 }, + }, + { + ID: "clean-aborted-uploads", + Status: "Enabled", + Filter: {}, + AbortIncompleteMultipartUpload: { DaysAfterInitiation: 7 }, + }, + { + ID: "expire-deleted-markers", + Status: "Enabled", + Filter: {}, + NoncurrentVersionExpiration: { NoncurrentDays: 30 }, + }, + ], + }, + })); + console.log(" ✓ Lifecycle rules set"); + } catch (err) { + console.log(" ✗ Lifecycle rules failed:", err.message); + } + + // Sample objects + const samples = [ + { key: "logs/access.log", body: "192.168.1.1 GET /api/v1/query 200 1234\n10.0.0.1 POST /api/v1/run 201 56\n" }, + { key: "logs/error.log", body: "2026-07-09 ERROR: Connection timeout to trino-worker-3\n2026-07-09 WARN: Retry attempt 2/5\n" }, + { key: "archive/2024/transactions.csv", body: "id,amount,currency,date\nTX-001,150.00,USD,2024-01-15\nTX-002,275.50,EUR,2024-03-22\nTX-003,89.99,GBP,2024-06-01\n" }, + { key: "archive/2024/audit.log", body: "[2024-01-01] System initialized\n[2024-06-30] Scheduled maintenance completed\n" }, + { key: "README.md", body: "# Test Bucket\n\nThis bucket is used for E2E testing of the Stackable Cockpit.\n" }, + { key: "config/cluster.yaml", body: "cluster:\n name: e2e-test\n replicas: 3\n storage: 100Gi\n" }, + ]; + + for (const { key, body } of samples) { + try { + await client.send(new PutObjectCommand({ + Bucket: bucket, + Key: key, + Body: body, + })); + console.log(" ✓ Uploaded:", key); + } catch (err) { + console.log(" ✗ Upload failed:", key, err.message); + } + } +} + +enrich().catch((err) => { + console.error("Fatal error during bucket enrichment:", err); + process.exit(1); +}); +' + cat > "$S3_CONFIG_PATH" < "$S3_CONFIG_PATH" < { + test.use({ locale: 'en-US' }); + + test('navigating between apps shows a loading indicator until the page is ready', async ({ + page + }) => { + await page.goto('/'); + await waitForHydration(page); + + // Delay the Trino route's data fetch so the loading indicator stays on + // screen long enough to assert on it. + await page.route('**/trino/__data.json*', async (route) => { + await new Promise((resolve) => setTimeout(resolve, 1500)); + await route.continue(); + }); + + await page.getByRole('link', { name: 'Trino', exact: true }).click(); + + const progress = page.locator('[data-navigation-progress]'); + await expect(progress).toBeVisible(); + await expect(progress.getByText('Loading…')).toBeVisible(); + + await expect(page.getByRole('heading', { name: 'Trino', exact: true })).toBeVisible(); + await expect(progress).toBeHidden(); + }); + + test('navigating within an app does not show the global loading bar', async ({ page }) => { + await page.goto('/storage'); + await waitForHydration(page); + + // Delay the connections page's data fetch. Even while it is in flight the + // global progress bar must stay hidden: it only appears between apps. + await page.route('**/settings/connections/__data.json*', async (route) => { + await new Promise((resolve) => setTimeout(resolve, 1500)); + await route.continue(); + }); + + await page.getByRole('link', { name: 'Manage connections' }).click(); + + const progress = page.locator('[data-navigation-progress]'); + await expect(progress).toBeHidden(); + // Wait out the artificial delay while the intra-app navigation is in flight. + await page.waitForTimeout(2000); + await expect(progress).toHaveCount(0); + + await expect(page.getByRole('heading', { name: 'Manage connections' })).toBeVisible(); + }); + + test('sidebar highlights the active app when switching between dashboard, Trino and storage', async ({ + page + }) => { + await page.goto('/'); + await waitForHydration(page); + + const dashboardLink = page.getByRole('link', { name: 'Dashboard' }); + const trinoLink = page.getByRole('link', { name: 'Trino', exact: true }); + const storageLink = page.getByRole('link', { name: 'Storage' }); + + await expect(dashboardLink).toHaveAttribute('aria-current', 'page'); + + await trinoLink.click(); + await expect(page.getByRole('heading', { name: 'Trino', exact: true })).toBeVisible(); + await expect(trinoLink).toHaveAttribute('aria-current', 'page'); + await expect(dashboardLink).not.toHaveAttribute('aria-current', 'page'); + + await storageLink.click(); + await expect(page.getByRole('heading', { name: 'Storage', exact: true })).toBeVisible(); + await expect(storageLink).toHaveAttribute('aria-current', 'page'); + await expect(trinoLink).not.toHaveAttribute('aria-current', 'page'); + + await dashboardLink.click(); + await expect(page.getByRole('heading', { name: 'Dashboard', exact: true })).toBeVisible(); + await expect(dashboardLink).toHaveAttribute('aria-current', 'page'); + await expect(storageLink).not.toHaveAttribute('aria-current', 'page'); + }); +}); diff --git a/e2e/run-garage-tests.sh b/e2e/run-garage-tests.sh deleted file mode 100755 index d5683b22..00000000 --- a/e2e/run-garage-tests.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) -S3_CONFIG_PATH="$ROOT_DIR/s3-config.json" - -if [[ ! -f "$S3_CONFIG_PATH" ]]; then - echo 's3-config.json was not found.' >&2 - echo 'Run dev/setup.sh to deploy Garage to your kind cluster (it writes s3-config.json).' >&2 - exit 1 -fi - -node --env-file=.env.test node_modules/.bin/vite build -# Run non-storage tests with full parallelism. -node_modules/.bin/playwright test e2e/auth/ e2e/trino/ e2e/smoke.spec.ts e2e/i18n.spec.ts "$@" -# Storage tests share a server-side S3 session per user and cannot run in -# parallel within the same browser project. Run them serially. -node_modules/.bin/playwright test e2e/storage/ --workers=1 "$@" diff --git a/e2e/smoke.spec.ts b/e2e/smoke.spec.ts index 271256ef..28d920af 100644 --- a/e2e/smoke.spec.ts +++ b/e2e/smoke.spec.ts @@ -5,8 +5,15 @@ test.describe('Smoke tests', () => { test.use({ locale: 'en-US' }); test('home page loads with app shell', async ({ page }) => { + // Firefox is slower to hydrate; triple the default timeout. + test.slow(); + await page.goto('/'); + // Wait for hydration so reactive state (page.url.pathname) has settled + // before checking aria-current, which depends on it. + await waitForHydration(page); + // Sidebar brand is visible await expect(page.getByText('Stackable', { exact: true })).toBeVisible(); @@ -28,6 +35,8 @@ test.describe('Smoke tests', () => { }); test('theme toggle switches between light and dark', async ({ page }) => { + // Firefox is slower to hydrate; triple the default timeout. + test.slow(); await page.goto('/'); const html = page.locator('html'); diff --git a/e2e/storage-s3.spec.ts b/e2e/storage-s3.spec.ts index 653cf5b0..896f600a 100644 --- a/e2e/storage-s3.spec.ts +++ b/e2e/storage-s3.spec.ts @@ -19,20 +19,38 @@ test.describe('Storage S3 (Garage)', () => { test.use({ locale: 'en-US' }); async function openConnectForm(page: import('@playwright/test').Page) { - await page.goto('/storage?disconnected=1'); + await page.goto('/storage'); await waitForHydration(page); const disconnectButton = page.getByRole('button', { name: 'Disconnect' }); if (await disconnectButton.isVisible().catch(() => false)) { await disconnectButton.click(); - // Disconnect now opens a confirmation modal — confirm it if it appears. - const confirmButton = page.getByRole('dialog').getByRole('button', { name: 'Disconnect' }); - if (await confirmButton.isVisible({ timeout: 2_000 }).catch(() => false)) { - await confirmButton.click(); - } + await page.getByRole('dialog').getByRole('button', { name: 'Disconnect' }).click(); } await expect(page.getByRole('heading', { name: 'Connect to storage' })).toBeVisible(); + + // Clear all saved connections so tests start from a clean state. + const savedList = page.getByRole('list', { name: 'Saved connections' }); + while (await savedList.isVisible().catch(() => false)) { + const items = savedList.getByRole('listitem'); + if ((await items.count()) === 0) break; + if ( + await items + .first() + .filter({ hasText: 'No saved connections yet' }) + .isVisible() + .catch(() => false) + ) + break; + await items.first().getByRole('button').last().click({ force: true }); + const deleteMenuItem = page.getByRole('menuitem', { name: 'Delete', exact: true }); + if (await deleteMenuItem.isVisible().catch(() => false)) { + await deleteMenuItem.click(); + await page.getByRole('button', { name: 'Delete', exact: true }).click(); + } + await waitForHydration(page); + } } test('connects to Garage S3 bucket and lists buckets', async ({ page }) => { @@ -60,16 +78,15 @@ test.describe('Storage S3 (Garage)', () => { await page.getByLabel('Access key').fill(accessKeyId); await page.getByLabel('Secret key').fill(secretAccessKey); - await page.getByRole('button', { name: 'Connect' }).click(); + await page.getByRole('button', { name: 'Connect', exact: true }).click(); // After a successful connection the app redirects to /storage and shows the bucket list await expect(page).toHaveURL('/storage'); const main = page.locator('main'); await expect(main.getByRole('heading', { name: 'Buckets' })).toBeVisible(); - // The bucket created during Garage setup must appear in the list. - // Both the sidebar nav and the bucket grid render a link — use first() to - // avoid a strict-mode violation. + // The bucket created during Garage setup must appear in the grid + // (use .first() because the sidebar nav also renders a link to each bucket) await expect(main.getByRole('link', { name: bucket, exact: true }).first()).toBeVisible(); }); @@ -95,11 +112,12 @@ test.describe('Storage S3 (Garage)', () => { await page.getByLabel('Region').fill(region); await page.getByLabel('Access key').fill(accessKeyId); await page.getByLabel('Secret key').fill(secretAccessKey); - await page.getByRole('button', { name: 'Connect' }).click(); + await page.getByRole('button', { name: 'Connect', exact: true }).click(); await expect(page.locator('main').getByRole('heading', { name: 'Buckets' })).toBeVisible(); // Then disconnect — clicking Disconnect opens a confirmation modal. await page.getByRole('button', { name: 'Disconnect' }).click(); + // Disconnect now shows a confirmation modal; confirm it await page.getByRole('dialog').getByRole('button', { name: 'Disconnect' }).click(); // Should return to the connect form diff --git a/e2e/storage/add-bucket.spec.ts b/e2e/storage/add-bucket.spec.ts new file mode 100644 index 00000000..9643c391 --- /dev/null +++ b/e2e/storage/add-bucket.spec.ts @@ -0,0 +1,162 @@ +import { test, expect } from '@playwright/test'; +import { + createGarageBucketCredentials, + hasGarageAdmin, + hasGarageCredentials, + requireGarageCredentials +} from '../support/garage.js'; +import { connectToStorage, modalBox, uniqueBucketName } from './helpers.js'; + +test.describe('Storage S3 — Add bucket manually', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + async function openAddBucketModal(page: import('@playwright/test').Page) { + await page.getByRole('button', { name: 'Add bucket' }).click(); + await expect(page.getByRole('dialog')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Connect to a bucket' })).toBeVisible(); + } + + test('opens and closes the Add bucket modal', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectToStorage(page, credentials); + await expect(page).toHaveURL('/storage'); + + await openAddBucketModal(page); + + await page.getByRole('button', { name: 'Cancel' }).click(); + await expect(page.getByRole('dialog')).not.toBeVisible(); + }); + + test('Connect button is disabled when input is empty', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectToStorage(page, credentials); + + await openAddBucketModal(page); + + await expect(modalBox(page).getByRole('button', { name: 'Connect' })).toBeDisabled(); + }); + + test('navigates into bucket after successful connection', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectToStorage(page, credentials); + await expect(page).toHaveURL('/storage'); + + await openAddBucketModal(page); + await modalBox(page).getByLabel('Bucket name').fill(credentials.bucket); + await modalBox(page).getByRole('button', { name: 'Connect' }).click(); + + await expect(page).toHaveURL( + `/storage/browse/${encodeURIComponent(new URL(credentials.endpoint).hostname)}/${encodeURIComponent(credentials.bucket)}` + ); + }); + + test('bucket appears in the bucket grid after successful connection', async ({ + page + }, testInfo) => { + test.skip( + !hasGarageAdmin(), + 'Skipped: Garage admin API is unavailable for per-test bucket setup' + ); + + const baseCredentials = requireGarageCredentials(); + const extraBucketName = uniqueBucketName(testInfo, 'manual-add'); + + // Connect before the extra bucket is created so it is absent from the initial listing. + // In Garage, AllowBucketKey with any permission causes the bucket to appear in ListBuckets, + // so we must create the bucket *after* the page has loaded to ensure it is not pre-listed. + await connectToStorage(page, baseCredentials); + await expect(page).toHaveURL('/storage'); + + // Create the extra bucket and grant the base key access now that the page is already loaded. + await createGarageBucketCredentials(baseCredentials, { + bucketName: extraBucketName, + keyName: `manual-${testInfo.project.name}-${crypto.randomUUID()}`, + permissions: { owner: false, read: true, write: false }, + ownerAccessKeyId: baseCredentials.accessKeyId + }); + + // The extra bucket should not be listed — it was created after the page loaded + const bucketLink = page.getByRole('link', { name: extraBucketName, exact: true }); + await expect(bucketLink.first()).not.toBeVisible(); + + // Add it manually + await openAddBucketModal(page); + await modalBox(page).getByLabel('Bucket name').fill(extraBucketName); + await modalBox(page).getByRole('button', { name: 'Connect' }).click(); + + // Should navigate into the bucket + await expect(page).toHaveURL( + `/storage/browse/${encodeURIComponent(new URL(baseCredentials.endpoint).hostname)}/${encodeURIComponent(extraBucketName)}` + ); + + // Go back to the bucket grid and confirm the bucket is now shown + await page.goto('/storage'); + await expect(bucketLink.first()).toBeVisible(); + }); + + test('shows access denied error for a bucket without read permission', async ({ + page + }, testInfo) => { + test.skip( + !hasGarageAdmin(), + 'Skipped: Garage admin API is unavailable for per-test bucket setup' + ); + + const baseCredentials = requireGarageCredentials(); + const blockedBucket = uniqueBucketName(testInfo, 'no-access'); + const noAccessCredentials = await createGarageBucketCredentials(baseCredentials, { + bucketName: blockedBucket, + keyName: `noaccess-${testInfo.project.name}-${crypto.randomUUID()}`, + permissions: { owner: false, read: false, write: false }, + ownerAccessKeyId: baseCredentials.accessKeyId + }); + + await connectToStorage(page, noAccessCredentials); + await expect(page).toHaveURL('/storage'); + + await openAddBucketModal(page); + await modalBox(page).getByLabel('Bucket name').fill(blockedBucket); + await modalBox(page).getByRole('button', { name: 'Connect' }).click(); + + await expect(modalBox(page).getByRole('alert')).toContainText('Access denied'); + + // Modal should remain open + await expect(page.getByRole('dialog')).toBeVisible(); + await expect(page).toHaveURL('/storage'); + }); + + test('shows not found error for a non-existent bucket', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectToStorage(page, credentials); + await expect(page).toHaveURL('/storage'); + + await openAddBucketModal(page); + await modalBox(page).getByLabel('Bucket name').fill('this-bucket-does-not-exist-xyz-99999'); + await modalBox(page).getByRole('button', { name: 'Connect' }).click(); + + await expect(modalBox(page).getByRole('alert')).toContainText('Bucket not found'); + + // Modal should remain open + await expect(page.getByRole('dialog')).toBeVisible(); + await expect(page).toHaveURL('/storage'); + }); + + test('resets form state after closing and reopening the modal', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectToStorage(page, credentials); + + await openAddBucketModal(page); + await modalBox(page).getByLabel('Bucket name').fill('some-value'); + await page.getByRole('button', { name: 'Cancel' }).click(); + + await openAddBucketModal(page); + await expect(modalBox(page).getByLabel('Bucket name')).toHaveValue(''); + }); +}); diff --git a/e2e/storage/archive.spec.ts b/e2e/storage/archive.spec.ts new file mode 100644 index 00000000..ae240cf0 --- /dev/null +++ b/e2e/storage/archive.spec.ts @@ -0,0 +1,351 @@ +import { PutObjectCommand } from '@aws-sdk/client-s3'; +import { test, expect } from '@playwright/test'; +import AdmZip from 'adm-zip'; +import { + createS3Client, + hasGarageCredentials, + requireGarageCredentials +} from '../support/garage.js'; +import { + connectAndOpenPrefix, + deleteKnownKeys, + rowByName, + uniquePrefix, + waitForObjectsLoaded +} from './helpers.js'; + +function makeZip(entries: Record): Buffer { + const zip = new AdmZip(); + for (const [name, content] of Object.entries(entries)) { + zip.addFile(name, Buffer.from(content, 'utf-8')); + } + return Buffer.from(zip.toBuffer()); +} + +test.describe('Storage S3 — Archive preview', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + test('opens archive by double-clicking and shows its contents', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'archive-open'); + const zipBuffer = makeZip({ + 'README.md': '# Archive test', + 'data/notes.txt': 'some notes', + 'data/results.csv': 'a,b,c\n1,2,3' + }); + const cleanupKeys = [`${prefix}archive.zip`]; + + try { + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}archive.zip`, + Body: zipBuffer, + ContentType: 'application/zip' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Double-click the archive file + await rowByName(page, 'archive.zip').dblclick(); + await waitForObjectsLoaded(page); + + // Should see archive contents — top-level folder and file + await expect(rowByName(page, 'README.md')).toBeVisible(); + await expect(rowByName(page, 'data')).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('navigates into directories within archive', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'archive-navigate'); + const zipBuffer = makeZip({ + 'a/b/c/file.txt': 'deep', + 'a/b/other.txt': 'other', + 'a/root.txt': 'root' + }); + const cleanupKeys = [`${prefix}archive.zip`]; + + try { + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}archive.zip`, + Body: zipBuffer, + ContentType: 'application/zip' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'archive.zip').dblclick(); + await waitForObjectsLoaded(page); + + // Navigate into a/ + await rowByName(page, 'a').click(); + await waitForObjectsLoaded(page); + await expect(rowByName(page, 'root.txt')).toBeVisible(); + await expect(rowByName(page, 'b')).toBeVisible(); + + // Navigate into b/ + await rowByName(page, 'b').click(); + await waitForObjectsLoaded(page); + await expect(rowByName(page, 'other.txt')).toBeVisible(); + await expect(rowByName(page, 'c')).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('previews text file inside archive', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'archive-preview'); + const zipBuffer = makeZip({ + 'hello.txt': 'Hello from inside archive!' + }); + const cleanupKeys = [`${prefix}archive.zip`]; + + try { + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}archive.zip`, + Body: zipBuffer, + ContentType: 'application/zip' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'archive.zip').dblclick(); + await waitForObjectsLoaded(page); + + // Double-click the text file inside archive + await rowByName(page, 'hello.txt').dblclick(); + + // Preview modal should show the file content + await expect(page.getByRole('heading', { name: 'hello.txt' })).toBeVisible(); + await expect(page.getByText('Hello from inside archive!')).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('exits archive via breadcrumb bucket click', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'archive-exit'); + const zipBuffer = makeZip({ 'file.txt': 'content' }); + const cleanupKeys = [`${prefix}archive.zip`]; + + try { + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}archive.zip`, + Body: zipBuffer, + ContentType: 'application/zip' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'archive.zip').dblclick(); + await waitForObjectsLoaded(page); + await expect(rowByName(page, 'file.txt')).toBeVisible(); + + // Click bucket name in breadcrumb to exit archive + await page.getByRole('button', { name: credentials.bucket }).click(); + await waitForObjectsLoaded(page); + + // Should be at the bucket root (archive exited) + + await expect(page).toHaveURL( + new RegExp( + `/storage/browse/${new URL(credentials.endpoint).hostname}/${credentials.bucket}(\\?|$)` + ) + ); + await expect(page.getByText('archive.zip')).not.toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('exits archive via parent directory row', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'archive-exit-parent'); + const zipBuffer = makeZip({ 'inner/file.txt': 'content' }); + const cleanupKeys = [`${prefix}archive.zip`]; + + try { + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}archive.zip`, + Body: zipBuffer, + ContentType: 'application/zip' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'archive.zip').dblclick(); + await waitForObjectsLoaded(page); + + // Navigate into inner/ + await rowByName(page, 'inner').click(); + await waitForObjectsLoaded(page); + await expect(rowByName(page, 'file.txt')).toBeVisible(); + + // Click parent directory ... + await rowByName(page, '...').click(); + await waitForObjectsLoaded(page); + await expect(rowByName(page, 'inner')).toBeVisible(); + + // Click ... again at archive root to exit + await rowByName(page, '...').click(); + await waitForObjectsLoaded(page); + await expect(rowByName(page, 'archive.zip')).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('opens nested archive inside another archive', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'archive-nested'); + + // Create inner zip + const innerZip = new AdmZip(); + innerZip.addFile('nested.txt', Buffer.from('nested content', 'utf-8')); + const innerBuf = Buffer.from(innerZip.toBuffer()); + + // Create outer zip containing the inner zip + const outerZip = new AdmZip(); + outerZip.addFile('outer.txt', Buffer.from('outer content', 'utf-8')); + outerZip.addFile('inner_archive.zip', innerBuf); + const outerBuf = Buffer.from(outerZip.toBuffer()); + + const cleanupKeys = [`${prefix}outer.zip`]; + + try { + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}outer.zip`, + Body: outerBuf, + ContentType: 'application/zip' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'outer.zip').dblclick(); + await waitForObjectsLoaded(page); + + // Should see outer archive contents + await expect(rowByName(page, 'outer.txt')).toBeVisible(); + await expect(rowByName(page, 'inner_archive.zip')).toBeVisible(); + + // Double-click the nested archive to enter it + await rowByName(page, 'inner_archive.zip').dblclick(); + await waitForObjectsLoaded(page); + + // Should see nested archive contents + await expect(rowByName(page, 'nested.txt')).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('shows archive breadcrumb and navigates back to archive root', async ({ + page + }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'archive-breadcrumb'); + const zipBuffer = makeZip({ + 'sub/readme.txt': 'hello', + 'sub/deep/doc.md': '# doc' + }); + const cleanupKeys = [`${prefix}archive.zip`]; + + try { + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}archive.zip`, + Body: zipBuffer, + ContentType: 'application/zip' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'archive.zip').dblclick(); + await waitForObjectsLoaded(page); + + // Navigate into sub/ + await rowByName(page, 'sub').click(); + await waitForObjectsLoaded(page); + await expect(rowByName(page, 'readme.txt')).toBeVisible(); + + // Navigate into deep/ + await rowByName(page, 'deep').click(); + await waitForObjectsLoaded(page); + await expect(rowByName(page, 'doc.md')).toBeVisible(); + + // Click archive name in breadcrumb to go back to archive root + await page.getByRole('button', { name: 'archive.zip' }).click(); + await waitForObjectsLoaded(page); + + // Should see archive root contents + await expect(rowByName(page, 'sub')).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('previews image file inside archive', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'archive-image'); + const svgContent = + ''; + const zipBuffer = makeZip({ 'diagram.svg': svgContent }); + const cleanupKeys = [`${prefix}archive.zip`]; + + try { + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}archive.zip`, + Body: zipBuffer, + ContentType: 'application/zip' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'archive.zip').dblclick(); + await waitForObjectsLoaded(page); + + // Double-click the SVG file + await rowByName(page, 'diagram.svg').dblclick(); + + // Preview modal should show image + await expect(page.getByRole('heading', { name: 'diagram.svg' })).toBeVisible(); + await expect(page.getByAltText('Preview of diagram.svg')).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); +}); diff --git a/e2e/storage/connection.spec.ts b/e2e/storage/connection.spec.ts index d74f1b7a..9a3b441c 100644 --- a/e2e/storage/connection.spec.ts +++ b/e2e/storage/connection.spec.ts @@ -40,12 +40,10 @@ test.describe('Storage S3 — Connection', () => { await page.getByLabel('Region').fill(credentials.region); await page.getByLabel('Access key').fill(credentials.accessKeyId); await page.getByLabel('Secret key').fill(`${credentials.secretAccessKey}-wrong`); - await page.getByRole('button', { name: 'Connect' }).click(); + await page.getByRole('button', { name: 'Connect', exact: true }).click(); await expect(page.getByRole('heading', { name: 'Connect to storage' })).toBeVisible(); - await expect( - page.getByText('Could not connect — check the endpoint and credentials.') - ).toBeVisible(); + await expect(page.getByText('Access denied — check your credentials.')).toBeVisible(); }); test('disconnects from Garage S3', async ({ page }) => { @@ -68,7 +66,8 @@ test.describe('Storage S3 — Connection', () => { await connectToStorage(page, credentials); await expect(page).toHaveURL('/storage'); - await openConnectForm(page); + // Do not clear saved connections — we need the one we just saved. + await openConnectForm(page, { clearSaved: false }); const savedList = page.getByRole('list', { name: 'Saved connections' }); await expect(savedList).toBeVisible(); @@ -85,12 +84,16 @@ test.describe('Storage S3 — Connection', () => { await connectToStorage(page, credentials); await expect(page).toHaveURL('/storage'); - await openConnectForm(page); + // Do not clear saved connections — we need the one we just saved. + await openConnectForm(page, { clearSaved: false }); const savedList = page.getByRole('list', { name: 'Saved connections' }); await expect(savedList).toBeVisible(); - // Open the "More options" context menu for the first saved connection + // Count items before — retries accumulate connections in the DB, so there + // may be more than one. We only assert that forgetting ONE removes exactly + // one entry, not that the list becomes empty. + const countBefore = await savedList.getByRole('listitem').count(); await savedList.getByRole('listitem').first().getByRole('button').last().click(); // Click Delete in the context menu (rendered as a menuitem) @@ -99,7 +102,13 @@ test.describe('Storage S3 — Connection', () => { // Confirm deletion in the modal await page.getByRole('button', { name: 'Delete', exact: true }).click(); - await expect(page.getByText('No saved connections yet')).toBeVisible(); + if (countBefore === 1) { + // Last connection removed — list collapses entirely + await expect(page.getByText('No saved connections yet')).toBeVisible(); + } else { + // Other connections still exist — list shrinks by exactly one + await expect(savedList.getByRole('listitem')).toHaveCount(countBefore - 1); + } }); test('clicking a bucket tile in the grid navigates to the bucket explorer', async ({ page }) => { @@ -115,7 +124,9 @@ test.describe('Storage S3 — Connection', () => { await expect(bucketLink).toBeVisible(); await bucketLink.click(); - await expect(page).toHaveURL(bucketRoute(credentials.bucket)); + await expect(page).toHaveURL( + bucketRoute(new URL(credentials.endpoint).hostname, credentials.bucket) + ); await expect(page.locator('nav[aria-label="breadcrumb"] [aria-current="page"]')).toContainText( credentials.bucket ); diff --git a/e2e/storage/connections-management.spec.ts b/e2e/storage/connections-management.spec.ts index 126ac9ac..0d9ef3f0 100644 --- a/e2e/storage/connections-management.spec.ts +++ b/e2e/storage/connections-management.spec.ts @@ -34,7 +34,7 @@ test.describe('Storage — Connections management', () => { await expect(page.getByRole('link', { name: 'Manage connections' })).toBeVisible(); }); - test('navigates to /storage/connections from the manage link', async ({ page }) => { + test('navigates to /settings/connections from the manage link', async ({ page }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); await openConnectForm(page); @@ -42,14 +42,14 @@ test.describe('Storage — Connections management', () => { await page.getByRole('link', { name: 'Manage connections' }).click(); await waitForHydration(page); - await expect(page).toHaveURL('/storage/connections'); + await expect(page).toHaveURL('/settings/connections'); await expect(page.getByRole('heading', { name: 'Manage connections' })).toBeVisible(); }); test('lists saved connections on the management page', async ({ page }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); // Connections are displayed in a table; at least one data row should be visible. @@ -59,7 +59,7 @@ test.describe('Storage — Connections management', () => { test('Edit link on management page navigates to edit page', async ({ page }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); await openFirstConnectionEditPage(page); @@ -70,7 +70,7 @@ test.describe('Storage — Connections management', () => { test('edit page pre-fills with current connection values', async ({ page }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); await openFirstConnectionEditPage(page); @@ -78,10 +78,8 @@ test.describe('Storage — Connections management', () => { await expect(page.getByRole('textbox', { name: 'Host' })).toHaveValue( new URL(credentials.endpoint).hostname ); - await expect(page.getByRole('textbox', { name: 'Region' })).toHaveValue(credentials.region); - await expect(page.getByRole('textbox', { name: 'Access key' })).toHaveValue( - credentials.accessKeyId - ); + await expect(page.getByLabel('Region')).toHaveValue(credentials.region); + await expect(page.getByLabel('Access key')).toHaveValue(credentials.accessKeyId); }); test('edit page redirects to connections list after saving valid credentials', async ({ @@ -89,7 +87,7 @@ test.describe('Storage — Connections management', () => { }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); await openFirstConnectionEditPage(page); @@ -97,14 +95,14 @@ test.describe('Storage — Connections management', () => { await page.getByRole('button', { name: 'Save changes' }).click(); await waitForHydration(page); - await expect(page).toHaveURL('/storage/connections'); + await expect(page).toHaveURL('/settings/connections'); await expect(page.getByRole('heading', { name: 'Manage connections' })).toBeVisible(); }); test('edit page shows error for invalid credentials', async ({ page }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); await openFirstConnectionEditPage(page); @@ -112,9 +110,7 @@ test.describe('Storage — Connections management', () => { await page.getByLabel('Secret key').fill('wrong-secret'); await page.getByRole('button', { name: 'Save changes' }).click(); - await expect( - page.getByText('Could not connect — check the endpoint and credentials.') - ).toBeVisible(); + await expect(page.getByText('Access denied — check your credentials.')).toBeVisible(); }); test('delete button on management page removes the connection after confirmation', async ({ @@ -122,7 +118,7 @@ test.describe('Storage — Connections management', () => { }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); // Connections are displayed in a table; count data rows (excluding header). @@ -141,11 +137,11 @@ test.describe('Storage — Connections management', () => { await expect(dataRows).toHaveCount(initialItems - 1); }); - test('redirects to /storage/connections when editing a non-existent id', async ({ page }) => { - await page.goto('/storage/connections/00000000-0000-0000-0000-000000000000/edit'); + test('redirects to /settings/connections when editing a non-existent id', async ({ page }) => { + await page.goto('/settings/connections/00000000-0000-0000-0000-000000000000/edit'); await waitForHydration(page); - await expect(page).toHaveURL('/storage/connections'); + await expect(page).toHaveURL('/settings/connections'); }); test('edit page shows active connection notice when editing current connection', async ({ @@ -153,7 +149,7 @@ test.describe('Storage — Connections management', () => { }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); await openFirstConnectionEditPage(page); @@ -166,7 +162,7 @@ test.describe('Storage — Connections management', () => { }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); await openFirstConnectionEditPage(page); @@ -175,7 +171,7 @@ test.describe('Storage — Connections management', () => { await page.getByLabel('Connection name').fill('Changed name'); // Try to navigate away via the back link - await page.getByRole('link', { name: '← Manage connections', exact: true }).click(); + await page.getByRole('link', { name: '← Manage connections' }).click(); // Modal should appear await expect(page.getByRole('dialog')).toBeVisible(); @@ -185,13 +181,13 @@ test.describe('Storage — Connections management', () => { test('unsaved-changes modal: Stay keeps user on edit page', async ({ page }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); await openFirstConnectionEditPage(page); await page.getByLabel('Connection name').fill('Changed name'); - await page.getByRole('link', { name: '← Manage connections', exact: true }).click(); + await page.getByRole('link', { name: '← Manage connections' }).click(); await page.getByRole('dialog').getByRole('button', { name: 'Stay on page' }).click(); @@ -202,17 +198,17 @@ test.describe('Storage — Connections management', () => { test('unsaved-changes modal: Leave navigates away', async ({ page }) => { const credentials = requireGarageCredentials(); await connectToStorage(page, credentials); - await page.goto('/storage/connections'); + await page.goto('/settings/connections'); await waitForHydration(page); await openFirstConnectionEditPage(page); await page.getByLabel('Connection name').fill('Changed name'); - await page.getByRole('link', { name: '← Manage connections', exact: true }).click(); + await page.getByRole('link', { name: '← Manage connections' }).click(); await page.getByRole('dialog').getByRole('button', { name: 'Leave' }).click(); await waitForHydration(page); - await expect(page).toHaveURL('/storage/connections'); + await expect(page).toHaveURL('/settings/connections'); }); }); diff --git a/e2e/storage/create.spec.ts b/e2e/storage/create.spec.ts new file mode 100644 index 00000000..7c374f0a --- /dev/null +++ b/e2e/storage/create.spec.ts @@ -0,0 +1,82 @@ +import { test, expect } from '@playwright/test'; +import { + createS3Client, + hasGarageCredentials, + requireGarageCredentials +} from '../support/garage.js'; +import { connectAndOpenPrefix, deleteKnownKeys, objectExists, uniquePrefix } from './helpers.js'; + +test.describe('Storage S3 — Create via context menu', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + test('creates a text file via empty-space right-click context menu', async ({ + page + }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'create-file'); + const newFile = `${prefix}hello.txt`; + const cleanupKeys = [newFile]; + + try { + await connectAndOpenPrefix(page, credentials, prefix); + + // Right-click on the empty-state row to trigger the empty-space context menu + await page.getByText('This bucket is empty').click({ button: 'right' }); + await expect(page.getByRole('menu')).toBeVisible(); + + await page.getByRole('menuitem', { name: 'New text file' }).click(); + + // The create modal appears with the name pre-filled + const input = page.locator('.modal-box input'); + await expect(input).toBeVisible(); + await input.fill('hello.txt'); + + await page.getByRole('dialog').getByRole('button', { name: 'Create' }).click(); + + // Wait for the file to appear in the listing + await page.waitForTimeout(1500); + + expect(await objectExists(client, credentials.bucket, newFile)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('creates a folder via empty-space right-click context menu', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'create-folder'); + const newFolder = `${prefix}my-folder/`; + const cleanupKeys = [newFolder]; + + try { + await connectAndOpenPrefix(page, credentials, prefix); + + await page.getByText('This bucket is empty').click({ button: 'right' }); + await expect(page.getByRole('menu')).toBeVisible(); + + await page.getByRole('menuitem', { name: 'New directory' }).click(); + + const input = page.locator('.modal-box input'); + await expect(input).toBeVisible(); + await input.fill('my-folder'); + + await page.getByRole('dialog').getByRole('button', { name: 'Create' }).click(); + + // Wait for the folder to appear in the listing + await page.waitForTimeout(1500); + + expect(await objectExists(client, credentials.bucket, newFolder)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); +}); diff --git a/e2e/storage/delete.spec.ts b/e2e/storage/delete.spec.ts index d647838f..d6b7ede8 100644 --- a/e2e/storage/delete.spec.ts +++ b/e2e/storage/delete.spec.ts @@ -119,4 +119,36 @@ test.describe('Storage S3 — Delete & Selection', () => { await deleteKnownKeys(client, credentials.bucket, cleanupKeys); } }); + + test('Delete keyboard shortcut opens the delete confirmation modal', async ({ + page + }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'kb-delete'); + const cleanupKeys = [`${prefix}delete-me.txt`]; + + try { + await putTextObject(client, credentials.bucket, `${prefix}delete-me.txt`, 'delete me'); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Select the file by clicking on the row + await rowByName(page, 'delete-me.txt').click(); + await expect(page.getByLabel('Select delete-me.txt')).toBeChecked(); + + // Press Delete key + await page.keyboard.press('Delete'); + + // Delete confirmation modal should appear + await expect(page.getByRole('heading', { name: /Delete.*delete-me.txt/i })).toBeVisible(); + await expect(page.getByText('This action cannot be undone.')).toBeVisible(); + + // Cancel the delete + await page.getByRole('button', { name: 'Cancel' }).click(); + await expect(page.getByRole('heading', { name: /Delete.*delete-me.txt/i })).not.toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); }); diff --git a/e2e/storage/details.spec.ts b/e2e/storage/details.spec.ts new file mode 100644 index 00000000..c1d1248b --- /dev/null +++ b/e2e/storage/details.spec.ts @@ -0,0 +1,88 @@ +import { test, expect } from '@playwright/test'; +import { + createS3Client, + hasGarageCredentials, + requireGarageCredentials +} from '../support/garage.js'; +import { + connectAndOpenPrefix, + connectToStorage, + deleteKnownKeys, + putDirectoryMarker, + putTextObject, + rowByName, + uniquePrefix +} from './helpers.js'; + +test.describe('Storage S3 — Details Modal', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + test('opens file details modal from context menu', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'details-file'); + const cleanupKeys = [`${prefix}test.txt`]; + + try { + await putTextObject(client, credentials.bucket, `${prefix}test.txt`, 'file details test'); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'test.txt').click({ button: 'right' }); + + await page.getByRole('menuitem', { name: 'Details' }).click(); + await expect(page.getByRole('heading', { name: 'File Details' })).toBeVisible(); + + await expect(page.getByText('test.txt').first()).toBeVisible(); + await expect( + page.getByText('s3://' + credentials.bucket + '/' + prefix + 'test.txt') + ).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('opens directory details modal from context menu', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'details-dir'); + const cleanupKeys = [`${prefix}subdir/`, `${prefix}subdir/file.txt`]; + + try { + await putDirectoryMarker(client, credentials.bucket, `${prefix}subdir/`); + await putTextObject(client, credentials.bucket, `${prefix}subdir/file.txt`, 'nested'); + + await connectAndOpenPrefix(page, credentials, prefix); + await rowByName(page, 'subdir').click({ button: 'right' }); + + await page.getByRole('menuitem', { name: 'Details' }).click(); + await expect(page.getByRole('heading', { name: 'Directory Details' })).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('opens bucket details from sidebar context menu', async ({ page }) => { + const credentials = requireGarageCredentials(); + const bucket = credentials.bucket; + + try { + await connectToStorage(page, credentials); + await expect(page).toHaveURL('/storage'); + + const sidebar = page.getByRole('navigation', { name: 'Buckets' }); + await sidebar.getByText(bucket).click({ button: 'right' }); + + await page.getByRole('menuitem', { name: 'Details' }).click(); + await expect(page.getByRole('heading', { name: 'Bucket Details' })).toBeVisible(); + } finally { + // no cleanup needed — using the shared test bucket + } + }); +}); diff --git a/e2e/storage/file-operations.spec.ts b/e2e/storage/file-operations.spec.ts new file mode 100644 index 00000000..6c880b6c --- /dev/null +++ b/e2e/storage/file-operations.spec.ts @@ -0,0 +1,486 @@ +import { test, expect } from '@playwright/test'; +import { + createS3Client, + hasGarageCredentials, + requireGarageCredentials +} from '../support/garage.js'; +import { + connectAndOpenPrefix, + deleteKnownKeys, + objectExists, + putDirectoryMarker, + putTextObject, + rowByName, + uniquePrefix, + getObjectText +} from './helpers.js'; + +test.describe('Storage S3 — File Operations', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + // ────────────────────────────────────────────────────────────────────────── + // Cut + Paste + // ────────────────────────────────────────────────────────────────────────── + + test('cut via context menu and paste moves file (original deleted)', async ({ + page + }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'cut-paste'); + const srcKey = `${prefix}source/`; + const srcFile = `${srcKey}cut-me.txt`; + const cleanupKeys = [srcFile, `${prefix}cut-me.txt`]; + + try { + await putDirectoryMarker(client, credentials.bucket, srcKey); + await putTextObject(client, credentials.bucket, srcFile, 'cut paste test'); + + await connectAndOpenPrefix(page, credentials, srcKey); + + // Right-click the file and choose Cut + await rowByName(page, 'cut-me.txt').click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Cut' }).click(); + + // Navigate to parent prefix in-app (preserves clipboard) + await page.locator('tbody tr').first().click(); + await page.waitForTimeout(500); + + // Click on table to focus it, then Ctrl+V to paste + await page.locator('table').click(); + await page.keyboard.press('Control+v'); + + await expect(page.getByText('1 item pasted')).toBeVisible(); + + // File should exist at dest (moved) + await expect + .poll(() => objectExists(client, credentials.bucket, `${prefix}cut-me.txt`)) + .toBe(true); + // Original should be deleted (cut = move) + await expect.poll(() => objectExists(client, credentials.bucket, srcFile)).toBe(false); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('pastes to a nested folder via context menu', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'cut-paste-nested'); + const srcFile = `${prefix}nested-src.txt`; + const destDir = `${prefix}target/`; + const cleanupKeys = [srcFile, destDir]; + + try { + await putTextObject(client, credentials.bucket, srcFile, 'nested paste'); + await putDirectoryMarker(client, credentials.bucket, destDir); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Copy file + await rowByName(page, 'nested-src.txt').click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Copy', exact: true }).click(); + + // Navigate into dest folder + await rowByName(page, 'target').dblclick(); + await page.waitForTimeout(500); + + // Paste (use keyboard shortcut — right-click in an empty folder + // lands on the ".." row which has no context menu handler) + await page.locator('table').click(); + await page.keyboard.press('Control+v'); + + await page.waitForTimeout(1000); + + expect(await objectExists(client, credentials.bucket, `${destDir}nested-src.txt`)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('paste with deleted source shows error toast', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'paste-deleted'); + const srcFile = `${prefix}gone.txt`; + const cleanupKeys = [srcFile]; + + try { + await putTextObject(client, credentials.bucket, srcFile, 'will be deleted'); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Copy the file + await rowByName(page, 'gone.txt').click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Copy', exact: true }).click(); + + // Delete the file via S3 directly (simulate race condition / out-of-band delete) + await deleteKnownKeys(client, credentials.bucket, [srcFile]); + + // Navigate to bucket root via ".." row (preserves clipboard) + await page.locator('tbody tr').first().click(); + await page.waitForTimeout(500); + + await page.locator('tbody').click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Paste' }).click(); + + await page.waitForTimeout(1000); + + // Should show error toast about source not found + const errorMsg = page.getByText(/could not paste|source.*deleted/i); + await expect(errorMsg).toBeVisible(); + + // The toast also has a Dismiss button + const toast = page.getByRole('alert').filter({ hasText: /could not paste|source.*deleted/i }); + const dismissBtn = toast.getByRole('button', { name: 'Dismiss' }); + await expect(dismissBtn).toBeVisible(); + await dismissBtn.click(); + await expect(toast).not.toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + // ────────────────────────────────────────────────────────────────────────── + // Copy + Paste (multiple destinations) + // ────────────────────────────────────────────────────────────────────────── + + test('copy and paste to multiple destinations', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'multi-paste'); + const srcFile = `${prefix}multi.txt`; + const dest1 = `${prefix}d1/`; + const dest2 = `${prefix}d2/`; + const cleanupKeys = [srcFile, dest1, dest2]; + + try { + await putTextObject(client, credentials.bucket, srcFile, 'multi paste'); + await putDirectoryMarker(client, credentials.bucket, dest1); + await putDirectoryMarker(client, credentials.bucket, dest2); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Copy file + await rowByName(page, 'multi.txt').click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Copy', exact: true }).click(); + + // Navigate into first destination and paste + await rowByName(page, 'd1').dblclick(); + await page.waitForTimeout(500); + await page.locator('table').click(); + await page.keyboard.press('Control+v'); + await page.waitForTimeout(1000); + + expect(await objectExists(client, credentials.bucket, `${dest1}multi.txt`)).toBe(true); + + // Navigate back to prefix then into second destination + await page.locator('tbody tr').first().click(); + await page.waitForTimeout(500); + await rowByName(page, 'd2').dblclick(); + await page.waitForTimeout(500); + await page.locator('table').click(); + await page.keyboard.press('Control+v'); + await page.waitForTimeout(1000); + + expect(await objectExists(client, credentials.bucket, `${dest2}multi.txt`)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + // ────────────────────────────────────────────────────────────────────────── + // Rename + // ────────────────────────────────────────────────────────────────────────── + + test('renames a file via context menu', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'rename'); + const oldKey = `${prefix}old-name.txt`; + const newKey = `${prefix}new-name.txt`; + const cleanupKeys = [oldKey, newKey]; + + try { + await putTextObject(client, credentials.bucket, oldKey, 'rename test'); + + await connectAndOpenPrefix(page, credentials, prefix); + + await rowByName(page, 'old-name.txt').click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Rename' }).click(); + + // Modal should be open with the name pre-filled and selected + const input = page.locator('.modal-box input'); + await expect(input).toBeVisible(); + + // Clear and type new name + await input.fill('new-name.txt'); + await page.getByRole('button', { name: 'Rename' }).click(); + + await page.waitForTimeout(1000); + + // Old name should be gone, new name should exist + expect(await objectExists(client, credentials.bucket, oldKey)).toBe(false); + expect(await objectExists(client, credentials.bucket, newKey)).toBe(true); + + // Content should be preserved + const content = await getObjectText(client, credentials.bucket, newKey); + expect(content).toBe('rename test'); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('rename conflict shows error inside modal', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'rename-conflict'); + const fileA = `${prefix}a.txt`; + const fileB = `${prefix}b.txt`; + const cleanupKeys = [fileA, fileB]; + + try { + await putTextObject(client, credentials.bucket, fileA, 'file a'); + await putTextObject(client, credentials.bucket, fileB, 'file b'); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Right-click file A and choose rename + await rowByName(page, 'a.txt').click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Rename' }).click(); + + // Try to rename to b.txt (which exists) + const input = page.locator('.modal-box input'); + await input.fill('b.txt'); + await page.getByRole('button', { name: 'Rename' }).click(); + + // Modal should stay open and show conflict error + await expect(page.locator('.modal-box')).toBeVisible(); + await expect(page.getByText(/already exists/i)).toBeVisible(); + + // Cancel the modal + await page.getByRole('button', { name: 'Cancel' }).click(); + await expect(page.locator('.modal-box')).not.toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + // ────────────────────────────────────────────────────────────────────────── + // Keyboard shortcuts + // ────────────────────────────────────────────────────────────────────────── + + test('Ctrl+C copies and Ctrl+V pastes a file', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'kb-copy-paste'); + const srcKey = `${prefix}src/`; + const srcFile = `${srcKey}kb-test.txt`; + const cleanupKeys = [srcFile]; + + try { + await putDirectoryMarker(client, credentials.bucket, srcKey); + await putTextObject(client, credentials.bucket, srcFile, 'kb test'); + + await connectAndOpenPrefix(page, credentials, srcKey); + + // Select the file + await rowByName(page, 'kb-test.txt').click(); + + // Press Ctrl+C to copy + await page.keyboard.press('Control+c'); + await page.waitForTimeout(300); + + // Navigate to parent prefix in-app (preserves clipboard) + await page.locator('tbody tr').first().click(); + await page.waitForTimeout(500); + + // Select somewhere to focus the page, then Ctrl+V + await page.locator('table').click(); + await page.keyboard.press('Control+v'); + + await page.waitForTimeout(1000); + + expect(await objectExists(client, credentials.bucket, `${prefix}kb-test.txt`)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('F2 renames a selected file', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'kb-rename'); + const oldKey = `${prefix}f2-old.txt`; + const newKey = `${prefix}f2-new.txt`; + const cleanupKeys = [oldKey, newKey]; + + try { + await putTextObject(client, credentials.bucket, oldKey, 'f2 rename'); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Select the file + await rowByName(page, 'f2-old.txt').click(); + + // Press F2 to open rename modal + await page.keyboard.press('F2'); + await expect(page.locator('.modal-box')).toBeVisible(); + + // Fill new name + const input = page.locator('.modal-box input'); + await input.fill('f2-new.txt'); + await page.keyboard.press('Enter'); + + await page.waitForTimeout(1000); + + expect(await objectExists(client, credentials.bucket, oldKey)).toBe(false); + expect(await objectExists(client, credentials.bucket, newKey)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('Ctrl+X cuts and Ctrl+V pastes a file', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'kb-cut-paste'); + const srcKey = `${prefix}cutsrc/`; + const srcFile = `${srcKey}cut-kb.txt`; + const cleanupKeys = [srcFile]; + + try { + await putDirectoryMarker(client, credentials.bucket, srcKey); + await putTextObject(client, credentials.bucket, srcFile, 'cut kb test'); + + await connectAndOpenPrefix(page, credentials, srcKey); + + // Select the file + await rowByName(page, 'cut-kb.txt').click(); + + // Ctrl+X to cut + await page.keyboard.press('Control+x'); + await page.waitForTimeout(300); + + // Navigate to parent prefix in-app (preserves clipboard) + await page.locator('tbody tr').first().click(); + await page.waitForTimeout(500); + + // Paste + await page.locator('table').click(); + await page.keyboard.press('Control+v'); + + await page.waitForTimeout(1000); + + // File should exist at destination + expect(await objectExists(client, credentials.bucket, `${prefix}cut-kb.txt`)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + // ────────────────────────────────────────────────────────────────────────── + // Drag-and-drop (move) + // ────────────────────────────────────────────────────────────────────────── + + test('drags a file onto a folder to move it', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'drag-move'); + const destFolder = `${prefix}dest-folder/`; + const srcFile = `${prefix}drag-me.txt`; + const destFile = `${destFolder}drag-me.txt`; + const cleanupKeys = [srcFile, destFolder]; + + try { + await putTextObject(client, credentials.bucket, srcFile, 'drag move test'); + await putDirectoryMarker(client, credentials.bucket, destFolder); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Get source row and destination folder row positions + const sourceRow = rowByName(page, 'drag-me.txt'); + const destRow = rowByName(page, 'dest-folder'); + + await sourceRow.dragTo(destRow); + + // Confirm the move in the dialog + await page.getByRole('button', { name: 'Move' }).click(); + + await page.waitForTimeout(2000); + + // File should be moved to destination folder + expect(await objectExists(client, credentials.bucket, srcFile)).toBe(false); + expect(await objectExists(client, credentials.bucket, destFile)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('drags a file onto parent directory row to move it up', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'drag-up'); + const subDir = `${prefix}sub/`; + const srcFile = `${subDir}up.txt`; + const cleanupKeys = [srcFile]; + + try { + await putDirectoryMarker(client, credentials.bucket, subDir); + await putTextObject(client, credentials.bucket, srcFile, 'move up'); + + await connectAndOpenPrefix(page, credentials, subDir); + + // Drag file onto parent directory ".." row + const sourceRow = rowByName(page, 'up.txt'); + const parentRow = page.locator('tbody tr').first(); // ".." parent row + + await sourceRow.dragTo(parentRow); + + // Confirm the move in the dialog + await page.getByRole('button', { name: 'Move' }).click(); + + await page.waitForTimeout(2000); + + // File should be at parent prefix + expect(await objectExists(client, credentials.bucket, `${prefix}up.txt`)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('cancels drag-and-drop move via confirmation dialog', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'drag-cancel'); + const destFolder = `${prefix}dest/`; + const srcFile = `${prefix}stay-here.txt`; + const cleanupKeys = [srcFile, destFolder]; + + try { + await putTextObject(client, credentials.bucket, srcFile, 'should not move'); + await putDirectoryMarker(client, credentials.bucket, destFolder); + + await connectAndOpenPrefix(page, credentials, prefix); + + const sourceRow = rowByName(page, 'stay-here.txt'); + const destRow = rowByName(page, 'dest'); + await sourceRow.dragTo(destRow); + + // Cancel the move + await page.getByRole('button', { name: 'Cancel' }).click(); + + // File should still be at original location + expect(await objectExists(client, credentials.bucket, srcFile)).toBe(true); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); +}); diff --git a/e2e/storage/helpers.ts b/e2e/storage/helpers.ts index 104e76b6..45978f90 100644 --- a/e2e/storage/helpers.ts +++ b/e2e/storage/helpers.ts @@ -25,9 +25,9 @@ export function uniqueBucketName(testInfo: TestInfo, scope: string): string { return `garage-${slug}-${testInfo.project.name.toLowerCase()}-${crypto.randomUUID().slice(0, 8)}`; } -export function bucketRoute(bucket: string, prefix = ''): string { +export function bucketRoute(connection: string, bucket: string, prefix = ''): string { if (!prefix) { - return `/storage/${encodeURIComponent(bucket)}`; + return `/storage/browse/${encodeURIComponent(connection)}/${encodeURIComponent(bucket)}`; } const trimmed = prefix.replace(/\/$/, ''); @@ -37,10 +37,41 @@ export function bucketRoute(bucket: string, prefix = ''): string { .map((segment) => encodeURIComponent(segment)) .join('/'); - return `/storage/${encodeURIComponent(bucket)}/${encoded}`; + return `/storage/browse/${encodeURIComponent(connection)}/${encodeURIComponent(bucket)}/${encoded}`; } -export async function openConnectForm(page: Page) { +export async function clearSavedConnections(page: Page) { + const savedList = page.getByRole('list', { name: 'Saved connections' }); + while (await savedList.isVisible().catch(() => false)) { + const items = savedList.getByRole('listitem'); + if ((await items.count()) === 0) break; + if ( + await items + .first() + .filter({ hasText: 'No saved connections yet' }) + .isVisible() + .catch(() => false) + ) + break; + // Click the last button in the first list item. On desktop this is the + // "more options" button (opacity-0, so use force). On mobile it's the + // X delete button which submits the form directly. + await items.first().getByRole('button').last().click({ force: true }); + // Desktop: a context menu appears — click Delete to open the modal. + // Mobile: the form submitted directly (no context menu), skip to hydration. + const deleteMenuItem = page.getByRole('menuitem', { name: 'Delete', exact: true }); + if (await deleteMenuItem.isVisible().catch(() => false)) { + await deleteMenuItem.click(); + // Confirm in the modal + await page.getByRole('button', { name: 'Delete', exact: true }).click(); + } + // The form action POSTs and the server redirects back to /storage; + // wait for the page to re-hydrate before checking the list again. + await waitForHydration(page); + } +} + +export async function openConnectForm(page: Page, { clearSaved = true } = {}) { await page.goto('/'); if (new URL(page.url()).pathname.startsWith('/auth/login')) { await waitForHydration(page); @@ -49,7 +80,7 @@ export async function openConnectForm(page: Page) { await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible(); } - await page.goto('/storage?disconnected=1'); + await page.goto('/storage'); await waitForHydration(page); const connectHeading = page.getByRole('heading', { name: 'Connect to storage' }); @@ -59,14 +90,17 @@ export async function openConnectForm(page: Page) { (await disconnectButton.isVisible().catch(() => false)) ) { await disconnectButton.click(); - // A confirmation modal was added — confirm the disconnection if the modal appears. - const confirmButton = page.locator('.modal-box').getByRole('button', { name: 'Disconnect' }); - if (await confirmButton.isVisible({ timeout: 2_000 }).catch(() => false)) { - await confirmButton.click(); - } + // Confirm the disconnect dialog + await page.getByRole('dialog').getByRole('button', { name: 'Disconnect' }).click(); } await expect(connectHeading).toBeVisible(); + + // Clear all saved connections so each test starts from a clean state and + // cannot be disrupted by connections left over from previous tests or retries. + if (clearSaved) { + await clearSavedConnections(page); + } } export async function connectToStorage(page: Page, credentials: GarageCredentials) { @@ -90,11 +124,12 @@ export async function connectToStorage(page: Page, credentials: GarageCredential await page.getByLabel('Region').fill(credentials.region); await page.getByLabel('Access key').fill(credentials.accessKeyId); await page.getByLabel('Secret key').fill(credentials.secretAccessKey); - await page.getByRole('button', { name: 'Connect' }).click(); - // Wait for the redirect to /storage so that saveConnectionLocally() has been called - // before the test navigates elsewhere. Without this, a fast page.goto() call can race - // with the in-flight form-submission fetch and the connection is never persisted. - await page.waitForURL((url) => url.pathname === '/storage', { timeout: 15_000 }); + await page.getByRole('button', { name: 'Connect', exact: true }).click(); + // Wait for the client-side connected state to be established before returning. + // This confirms the session's activeStorageConnectionId is set and the layout + // has fetched the bucket list — reducing the window for session race conditions + // when parallel workers share the same server-side session. + await waitForStorageConnected(page); } export async function connectAndOpenPrefix( @@ -103,8 +138,32 @@ export async function connectAndOpenPrefix( prefix = '' ) { await connectToStorage(page, credentials); - await expect(page).toHaveURL('/storage'); - await page.goto(bucketRoute(credentials.bucket, prefix)); + const connection = new URL(credentials.endpoint).hostname; + const route = bucketRoute(connection, credentials.bucket, prefix); + + // A session update can redirect a just-opened bucket route to the storage + // overview after hydration. Retry once if that happens while loading. + for (let attempt = 0; attempt < 2; attempt += 1) { + await page.goto(route); + await waitForHydration(page); + + const objectsLoaded = page + .locator('tbody tr') + .or(page.getByText('This bucket is empty')) + .first() + .waitFor({ timeout: 15_000 }); + const storageOverview = page.getByRole('heading', { name: 'Buckets', exact: true }).waitFor({ + timeout: 15_000 + }); + + await Promise.race([objectsLoaded, storageOverview]); + if (page.url().includes(encodeURIComponent(credentials.bucket))) { + return; + } + + await connectToStorage(page, credentials); + } + await waitForObjectsLoaded(page); } @@ -218,3 +277,19 @@ export async function headObject(client: S3Client, bucket: string, key: string) // Re-export expect for convenience export { expect }; + +/** Seeds the `storage_tabs` localStorage key before the first page load of a + * test, simulating a previous session's saved tab state. Because this uses + * `addInitScript` it runs on every navigation within the test context, so the + * data is available regardless of which page triggers the initial load. */ +export async function seedStorageTabsState( + page: Page, + state: { + tabs: Array<{ id: string; label: string; bucket: string; prefix: string; connection?: string }>; + activeTabId: string; + } +): Promise { + await page.addInitScript((data) => { + localStorage.setItem('storage_tabs', JSON.stringify(data)); + }, state); +} diff --git a/e2e/storage/permissions.spec.ts b/e2e/storage/permissions.spec.ts index b9b2f467..c6af1cf2 100644 --- a/e2e/storage/permissions.spec.ts +++ b/e2e/storage/permissions.spec.ts @@ -104,7 +104,7 @@ test.describe('Storage S3 — Permissions', () => { await connectToStorage(page, writeonlyCredentials); await expect(page.locator('main').getByRole('heading', { name: 'Buckets' })).toBeVisible(); - await page.goto(bucketRoute(writeonlyBucket)); + await page.goto(bucketRoute(new URL(baseCredentials.endpoint).hostname, writeonlyBucket)); await expect(page.getByText('403')).toBeVisible(); await expect(page.getByText('You do not have permission to access the bucket')).toBeVisible(); @@ -128,7 +128,7 @@ test.describe('Storage S3 — Permissions', () => { await connectToStorage(page, noAccessCredentials); await expect(page).toHaveURL('/storage'); - await page.goto(bucketRoute(noAccessBucket)); + await page.goto(bucketRoute(new URL(baseCredentials.endpoint).hostname, noAccessBucket)); await expect(page.getByText('403')).toBeVisible(); await expect(page.getByText('You do not have permission to access the bucket')).toBeVisible(); diff --git a/e2e/storage/preview.spec.ts b/e2e/storage/preview.spec.ts index 84bd1b52..744f1e7a 100644 --- a/e2e/storage/preview.spec.ts +++ b/e2e/storage/preview.spec.ts @@ -44,41 +44,13 @@ test.describe('Storage S3 — Preview', () => { await expect(page.getByText('Preview line one')).toBeVisible(); await expect(page.getByText('Preview line two')).toBeVisible(); - await page.getByRole('button', { name: 'Close' }).last().click(); + await page.getByRole('dialog').getByRole('button', { name: 'Close', exact: true }).click(); await expect(page.getByRole('heading', { name: 'preview.txt' })).not.toBeVisible(); } finally { await deleteKnownKeys(client, credentials.bucket, cleanupKeys); } }); - test('shows fallback preview for a known binary file type', async ({ page }, testInfo) => { - const credentials = requireGarageCredentials(); - const client = createS3Client(credentials); - const prefix = uniquePrefix(testInfo, 'preview-zip'); - const cleanupKeys = [`${prefix}archive.zip`]; - - try { - await client.send( - new PutObjectCommand({ - Bucket: credentials.bucket, - Key: `${prefix}archive.zip`, - Body: Buffer.from([0x50, 0x4b, 0x03, 0x04, 0x00, 0x00]), - ContentType: 'application/zip' - }) - ); - - await connectAndOpenPrefix(page, credentials, prefix); - - await rowByName(page, 'archive.zip').dblclick(); - - await expect(page.getByRole('heading', { name: 'archive.zip' })).toBeVisible(); - await expect(page.getByText('Preview unavailable')).toBeVisible(); - await expect(page.getByRole('button', { name: 'Download full file' })).toBeVisible(); - } finally { - await deleteKnownKeys(client, credentials.bucket, cleanupKeys); - } - }); - test('shows binary fallback preview for non-decodable binary content', async ({ page }, testInfo) => { @@ -277,6 +249,246 @@ test.describe('Storage S3 — Preview', () => { } }); + test('previews parquet files with column headers and data rows', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'preview-parquet'); + const cleanupKeys = [`${prefix}data.parquet`]; + + try { + // A minimal valid parquet file generated by pyarrow: + // id | name | score + // 1 | Alice | 95.5 + // 2 | Bob | 87.0 + // 3 | Charlie | 72.3 + const parquetBase64 = + 'UEFSMRUEFSAVIEwVBBUAEgAAAQAAAAAAAAACAAAAAAAAABUAFRIVEiwVBBUQFQYVBhwYCAIAAAAAAAAAGAgBAAAAAAAAABYAKAgCAAAAAAAAABgIAQAAAAAAAAAREQAAAAIAAAAEAQEDAhUEFSAVIEwVBBUAEgAABQAAAEFsaWNlAwAAAEJvYhUAFRIVEiwVBBUQFQYVBhw2ACgDQm9iGAVBbGljZRERAAAAAgAAAAQBAQMCFQQVIBUgTBUEFQASAAAAAAAAAOBXQAAAAAAAwFVAFQAVEhUSLBUEFRAVBhUGHBgIAAAAAADgV0AYCAAAAAAAwFVAFgAoCAAAAAAA4FdAGAgAAAAAAMBVQBERAAAAAgAAAAQBAQMCFQQVEBUQTBUCFQASAAADAAAAAAAAABUAFRIVEiwVAhUQFQYVBhwYCAMAAAAAAAAAGAgDAAAAAAAAABYAKAgDAAAAAAAAABgIAwAAAAAAAAAREQAAAAIAAAACAQECABUEFRYVFkwVAhUAEgAABwAAAENoYXJsaWUVABUSFRIsFQIVEBUGFQYcNgAoB0NoYXJsaWUYB0NoYXJsaWUREQAAAAIAAAACAQECABUEFRAVEEwVAhUAEgAAMzMzMzMTUkAVABUSFRIsFQIVEBUGFQYcGAgzMzMzMxNSQBgIMzMzMzMTUkAWACgIMzMzMzMTUkAYCDMzMzMzE1JAEREAAAACAAAAAgEBAgAVBBlMNQAYBnNjaGVtYRUGABUEJQIYAmlkABUMJQIYBG5hbWUlAEwcAAAAFQolAhgFc2NvcmUAFgYZLBk8JgAcFQQZNQAGEBkYAmlkFQAWBBbMARbMASZEJggcGAgCAAAAAAAAABgIAQAAAAAAAAAWACgIAgAAAAAAAAAYCAEAAAAAAAAAEREAGSwVBBUAFQIAFQAVEBUCADwpBhkmAAQAAAAmABwVDBk1AAYQGRgEbmFtZRUAFgQWlAEWlAEmkAIm1AEcNgAoA0JvYhgFQWxpY2UREQAZLBUEFQAVAgAVABUQFQIAPBYQGQYZJgAEAAAAJgAcFQoZNQAGEBkYBXNjb3JlFQAWBBbMARbMASakAyboAhwYCAAAAAAA4FdAGAgAAAAAAMBVQBYAKAgAAAAAAOBXQBgIAAAAAADAVUAREQAZLBUEFQAVAgAVABUQFQIAPCkGGSYABAAAABasBBYEJggWrAQAGTwmABwVBBk1AAYQGRgCaWQVABYCFrwBFrwBJuAEJrQEHBgIAwAAAAAAAAAYCAMAAAAAAAAAFgAoCAMAAAAAAAAAGAgDAAAAAAAAABERABksFQQVABUCABUAFRAVAgA8KQYZJgACAAAAJgAcFQwZNQAGEBkYBG5hbWUVABYCFpYBFpYBJqIGJvAFHDYAKAdDaGFybGllGAdDaGFybGllEREAGSwVBBUAFQIAFQAVEBUCADwWDhkGGSYAAgAAACYAHBUKGTUABhAZGAVzY29yZRUAFgIWvAEWvAEmsgcmhgccGAgzMzMzMxNSQBgIMzMzMzMTUkAWACgIMzMzMzMTUkAYCDMzMzMzE1JAEREAGSwVBBUAFQIAFQAVEBUCADwpBhkmAAIAAAAWjgQWAia0BBaOBAAZHBgMQVJST1c6c2NoZW1hGLgCLy8vLy8rQUFBQUFRQUFBQUFBQUtBQXdBQmdBRkFBZ0FDZ0FBQUFBQkJBQU1BQUFBQ0FBSUFBQUFCQUFJQUFBQUJBQUFBQU1BQUFCNEFBQUFPQUFBQUFRQUFBQ2svLy8vQUFBQkF4QUFBQUFjQUFBQUJBQUFBQUFBQUFBRkFBQUFjMk52Y21VQUJnQUlBQVlBQmdBQUFBQUFBZ0RVLy8vL0FBQUJCUkFBQUFBY0FBQUFCQUFBQUFBQUFBQUVBQUFBYm1GdFpRQUFBQUFFQUFRQUJBQUFBQkFBRkFBSUFBWUFCd0FNQUFBQUVBQVFBQUFBQUFBQkFoQUFBQUFjQUFBQUJBQUFBQUFBQUFBQ0FBQUFhV1FBQUFnQURBQUlBQWNBQ0FBQUFBQUFBQUZBQUFBQUFBQUFBQT09ABggcGFycXVldC1jcHAtYXJyb3cgdmVyc2lvbiAyNC4wLjAZPBwAABwAABwAAAAUBAAAUEFSMQ=='; + + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}data.parquet`, + Body: Buffer.from(parquetBase64, 'base64'), + ContentType: 'application/vnd.apache.parquet' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + + await rowByName(page, 'data.parquet').dblclick(); + + // Modal heading + await expect(page.getByRole('heading', { name: 'data.parquet' })).toBeVisible(); + + // Default view is Metadata tab — schema column names should be visible in the Schema table + const schemaTable = page.getByRole('table', { name: 'Schema' }); + await expect(schemaTable.getByRole('cell', { name: 'id' })).toBeVisible(); + await expect(schemaTable.getByRole('cell', { name: 'name' })).toBeVisible(); + await expect(schemaTable.getByRole('cell', { name: 'score' })).toBeVisible(); + + // Tabs are visible + await expect(page.getByRole('tab', { name: 'Metadata' })).toBeVisible(); + await expect(page.getByRole('tab', { name: 'Data', exact: true })).toBeVisible(); + + // Click the Data tab to view the data table + await page.getByRole('tab', { name: 'Data', exact: true }).click(); + + // Parquet preview table with correct aria label + const table = page.getByRole('table', { name: 'Parquet preview' }); + await expect(table).toBeVisible(); + + // Column headers in data table + await expect(table.locator('th', { hasText: 'id' })).toBeVisible(); + await expect(table.locator('th', { hasText: 'name' })).toBeVisible(); + await expect(table.locator('th', { hasText: 'score' })).toBeVisible(); + + // Data rows + await expect(table.locator('td', { hasText: 'Alice' })).toBeVisible(); + await expect(table.locator('td', { hasText: 'Bob' })).toBeVisible(); + await expect(table.locator('td', { hasText: 'Charlie' })).toBeVisible(); + + // File size badge + await expect(page.locator('.badge', { hasText: /B$/ })).toBeVisible(); + + // Close button works + await page.getByRole('button', { name: 'Close' }).last().click(); + await expect(page.getByRole('heading', { name: 'data.parquet' })).not.toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('previews parquet file with application/x-parquet content type', async ({ + page + }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'preview-parquet-x'); + const cleanupKeys = [`${prefix}measurements.parquet`]; + + try { + const parquetBase64 = + 'UEFSMRUEFSAVIEwVBBUAEgAAAQAAAAAAAAACAAAAAAAAABUAFRIVEiwVBBUQFQYVBhwYCAIAAAAAAAAAGAgBAAAAAAAAABYAKAgCAAAAAAAAABgIAQAAAAAAAAAREQAAAAIAAAAEAQEDAhUEFSAVIEwVBBUAEgAABQAAAEFsaWNlAwAAAEJvYhUAFRIVEiwVBBUQFQYVBhw2ACgDQm9iGAVBbGljZRERAAAAAgAAAAQBAQMCFQQVIBUgTBUEFQASAAAAAAAAAOBXQAAAAAAAwFVAFQAVEhUSLBUEFRAVBhUGHBgIAAAAAADgV0AYCAAAAAAAwFVAFgAoCAAAAAAA4FdAGAgAAAAAAMBVQBERAAAAAgAAAAQBAQMCFQQVEBUQTBUCFQASAAADAAAAAAAAABUAFRIVEiwVAhUQFQYVBhwYCAMAAAAAAAAAGAgDAAAAAAAAABYAKAgDAAAAAAAAABgIAwAAAAAAAAAREQAAAAIAAAACAQECABUEFRYVFkwVAhUAEgAABwAAAENoYXJsaWUVABUSFRIsFQIVEBUGFQYcNgAoB0NoYXJsaWUYB0NoYXJsaWUREQAAAAIAAAACAQECABUEFRAVEEwVAhUAEgAAMzMzMzMTUkAVABUSFRIsFQIVEBUGFQYcGAgzMzMzMxNSQBgIMzMzMzMTUkAWACgIMzMzMzMTUkAYCDMzMzMzE1JAEREAAAACAAAAAgEBAgAVBBlMNQAYBnNjaGVtYRUGABUEJQIYAmlkABUMJQIYBG5hbWUlAEwcAAAAFQolAhgFc2NvcmUAFgYZLBk8JgAcFQQZNQAGEBkYAmlkFQAWBBbMARbMASZEJggcGAgCAAAAAAAAABgIAQAAAAAAAAAWACgIAgAAAAAAAAAYCAEAAAAAAAAAEREAGSwVBBUAFQIAFQAVEBUCADwpBhkmAAQAAAAmABwVDBk1AAYQGRgEbmFtZRUAFgQWlAEWlAEmkAIm1AEcNgAoA0JvYhgFQWxpY2UREQAZLBUEFQAVAgAVABUQFQIAPBYQGQYZJgAEAAAAJgAcFQoZNQAGEBkYBXNjb3JlFQAWBBbMARbMASakAyboAhwYCAAAAAAA4FdAGAgAAAAAAMBVQBYAKAgAAAAAAOBXQBgIAAAAAADAVUAREQAZLBUEFQAVAgAVABUQFQIAPCkGGSYABAAAABasBBYEJggWrAQAGTwmABwVBBk1AAYQGRgCaWQVABYCFrwBFrwBJuAEJrQEHBgIAwAAAAAAAAAYCAMAAAAAAAAAFgAoCAMAAAAAAAAAGAgDAAAAAAAAABERABksFQQVABUCABUAFRAVAgA8KQYZJgACAAAAJgAcFQwZNQAGEBkYBG5hbWUVABYCFpYBFpYBJqIGJvAFHDYAKAdDaGFybGllGAdDaGFybGllEREAGSwVBBUAFQIAFQAVEBUCADwWDhkGGSYAAgAAACYAHBUKGTUABhAZGAVzY29yZRUAFgIWvAEWvAEmsgcmhgccGAgzMzMzMxNSQBgIMzMzMzMTUkAWACgIMzMzMzMTUkAYCDMzMzMzE1JAEREAGSwVBBUAFQIAFQAVEBUCADwpBhkmAAIAAAAWjgQWAia0BBaOBAAZHBgMQVJST1c6c2NoZW1hGLgCLy8vLy8rQUFBQUFRQUFBQUFBQUtBQXdBQmdBRkFBZ0FDZ0FBQUFBQkJBQU1BQUFBQ0FBSUFBQUFCQUFJQUFBQUJBQUFBQU1BQUFCNEFBQUFPQUFBQUFRQUFBQ2svLy8vQUFBQkF4QUFBQUFjQUFBQUJBQUFBQUFBQUFBRkFBQUFjMk52Y21VQUJnQUlBQVlBQmdBQUFBQUFBZ0RVLy8vL0FBQUJCUkFBQUFBY0FBQUFCQUFBQUFBQUFBQUVBQUFBYm1GdFpRQUFBQUFFQUFRQUJBQUFBQkFBRkFBSUFBWUFCd0FNQUFBQUVBQVFBQUFBQUFBQkFoQUFBQUFjQUFBQUJBQUFBQUFBQUFBQ0FBQUFhV1FBQUFnQURBQUlBQWNBQ0FBQUFBQUFBQUZBQUFBQUFBQUFBQT09ABggcGFycXVldC1jcHAtYXJyb3cgdmVyc2lvbiAyNC4wLjAZPBwAABwAABwAAAAUBAAAUEFSMQ=='; + + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}measurements.parquet`, + Body: Buffer.from(parquetBase64, 'base64'), + ContentType: 'application/x-parquet' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + + await rowByName(page, 'measurements.parquet').dblclick(); + + await expect(page.getByRole('heading', { name: 'measurements.parquet' })).toBeVisible(); + + // Schema column names should be visible in default metadata tab + await expect( + page.getByRole('table', { name: 'Schema' }).getByRole('cell', { name: 'name' }) + ).toBeVisible(); + + // Click Data tab to view data table + await page.getByRole('tab', { name: 'Data', exact: true }).click(); + const table = page.getByRole('table', { name: 'Parquet preview' }); + await expect(table).toBeVisible(); + await expect(table.locator('th', { hasText: 'name' })).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('previews TSV files with table headers and data rows', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'preview-tsv'); + const cleanupKeys = [`${prefix}data.tsv`]; + + try { + const tsvContent = ['name\tcity\tscore', 'Alice\tBerlin\t95', 'Bob\tMunich\t88'].join('\n'); + + await putTextObject( + client, + credentials.bucket, + `${prefix}data.tsv`, + tsvContent, + 'text/tab-separated-values' + ); + + await connectAndOpenPrefix(page, credentials, prefix); + + await rowByName(page, 'data.tsv').dblclick(); + + // Modal heading + await expect(page.getByRole('heading', { name: 'data.tsv' })).toBeVisible(); + + // CSV/TSV table is rendered with correct aria label + const table = page.getByRole('table', { name: 'CSV preview' }); + await expect(table).toBeVisible(); + + // Headers are present + await expect(table.locator('th', { hasText: 'name' })).toBeVisible(); + await expect(table.locator('th', { hasText: 'city' })).toBeVisible(); + await expect(table.locator('th', { hasText: 'score' })).toBeVisible(); + + // Data rows are present + await expect(table.locator('td', { hasText: 'Alice' })).toBeVisible(); + await expect(table.locator('td', { hasText: 'Berlin' })).toBeVisible(); + await expect(table.locator('td', { hasText: '95' })).toBeVisible(); + await expect(table.locator('td', { hasText: 'Bob' })).toBeVisible(); + + // File size badge is displayed + await expect(page.locator('.badge', { hasText: /B$/ })).toBeVisible(); + + // Close button works + await page.getByRole('button', { name: 'Close' }).last().click(); + await expect(page.getByRole('heading', { name: 'data.tsv' })).not.toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('previews TSV files with quoted fields containing tabs', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'preview-tsv-quoted'); + const cleanupKeys = [`${prefix}notes.tsv`]; + + try { + const tsvContent = ['name\tnotes', 'Alice\t"likes\ttabs\tin\tdata"', 'Bob\tplain text'].join( + '\n' + ); + + await putTextObject( + client, + credentials.bucket, + `${prefix}notes.tsv`, + tsvContent, + 'text/tab-separated-values' + ); + + await connectAndOpenPrefix(page, credentials, prefix); + + await rowByName(page, 'notes.tsv').dblclick(); + + await expect(page.getByRole('heading', { name: 'notes.tsv' })).toBeVisible(); + + const table = page.getByRole('table', { name: 'CSV preview' }); + await expect(table).toBeVisible(); + + // Quoted fields with tabs are parsed correctly + await expect(table.locator('td', { hasText: 'likes\ttabs\tin\tdata' })).toBeVisible(); + await expect(table.locator('td', { hasText: 'plain text' })).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + + test('previews TSV files with application/vnd.ms-excel content type', async ({ + page + }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'preview-tsv-excel'); + const cleanupKeys = [`${prefix}export.tsv`]; + + try { + const tsvContent = ['product\tprice\tqty', 'Widget\t19.99\t100', 'Gadget\t49.95\t50'].join( + '\n' + ); + + await client.send( + new PutObjectCommand({ + Bucket: credentials.bucket, + Key: `${prefix}export.tsv`, + Body: Buffer.from(tsvContent), + ContentType: 'application/vnd.ms-excel' + }) + ); + + await connectAndOpenPrefix(page, credentials, prefix); + + await rowByName(page, 'export.tsv').dblclick(); + + await expect(page.getByRole('heading', { name: 'export.tsv' })).toBeVisible(); + + const table = page.getByRole('table', { name: 'CSV preview' }); + await expect(table).toBeVisible(); + + await expect(table.locator('th', { hasText: 'product' })).toBeVisible(); + await expect(table.locator('th', { hasText: 'price' })).toBeVisible(); + await expect(table.locator('th', { hasText: 'qty' })).toBeVisible(); + + await expect(table.locator('td', { hasText: 'Widget' })).toBeVisible(); + await expect(table.locator('td', { hasText: '19.99' })).toBeVisible(); + await expect(table.locator('td', { hasText: '100' })).toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); + test('closes preview modal when the Escape key is pressed', async ({ page }, testInfo) => { const credentials = requireGarageCredentials(); const client = createS3Client(credentials); diff --git a/e2e/storage/recent-items.spec.ts b/e2e/storage/recent-items.spec.ts index 9a53f2b7..9b7a9db0 100644 --- a/e2e/storage/recent-items.spec.ts +++ b/e2e/storage/recent-items.spec.ts @@ -19,7 +19,8 @@ import { async function previewFile(page: Page, name: string) { await rowByName(page, name).dblclick(); await expect(page.getByRole('heading', { name })).toBeVisible(); - await page.getByRole('button', { name: 'Close' }).last().click(); + await page.getByRole('dialog').getByRole('button', { name: 'Close', exact: true }).click(); + await expect(page.getByRole('heading', { name })).not.toBeVisible(); } test.describe('Storage S3 — Recent Items', () => { @@ -37,7 +38,7 @@ test.describe('Storage S3 — Recent Items', () => { await connectToStorage(page, credentials); await expect(page).toHaveURL('/storage'); - await page.goto(bucketRoute(credentials.bucket)); + await page.goto(bucketRoute(new URL(credentials.endpoint).hostname, credentials.bucket)); await waitForObjectsLoaded(page); await page.goto('/storage'); @@ -62,7 +63,7 @@ test.describe('Storage S3 — Recent Items', () => { await connectAndOpenPrefix(page, credentials, prefix); await rowByName(page, 'recent.txt').dblclick(); await expect(page.getByRole('heading', { name: 'recent.txt' })).toBeVisible(); - await page.getByRole('button', { name: 'Close' }).last().click(); + await page.getByRole('dialog').getByRole('button', { name: 'Close', exact: true }).click(); await page.goto('/storage'); await waitForStorageConnected(page); @@ -74,6 +75,7 @@ test.describe('Storage S3 — Recent Items', () => { }); test('removes a deleted file from Recent Files', async ({ page }, testInfo) => { + test.slow(); // multiple navigations + deletion; Firefox is slow in CI const credentials = requireGarageCredentials(); const client = createS3Client(credentials); const prefix = uniquePrefix(testInfo, 'recent-delete-file'); @@ -92,7 +94,9 @@ test.describe('Storage S3 — Recent Items', () => { await expect(page.locator('tbody').getByText('to-delete.txt')).toBeVisible(); // Delete the file via the UI - await page.goto(bucketRoute(credentials.bucket, prefix)); + await page.goto( + bucketRoute(new URL(credentials.endpoint).hostname, credentials.bucket, prefix) + ); await waitForObjectsLoaded(page); await page.getByRole('button', { name: 'Toggle selection mode' }).click(); await page.getByLabel('Select to-delete.txt').check(); @@ -112,6 +116,7 @@ test.describe('Storage S3 — Recent Items', () => { test('removes files and location from recent lists when a directory is deleted', async ({ page }, testInfo) => { + test.slow(); // multiple navigations + directory deletion; Firefox is slow const credentials = requireGarageCredentials(); const client = createS3Client(credentials); const prefix = uniquePrefix(testInfo, 'recent-delete-dir'); @@ -134,7 +139,9 @@ test.describe('Storage S3 — Recent Items', () => { await expect(page.locator('tbody').getByText('sub', { exact: true })).toBeVisible(); // Delete the parent directory via the UI - await page.goto(bucketRoute(credentials.bucket, prefix)); + await page.goto( + bucketRoute(new URL(credentials.endpoint).hostname, credentials.bucket, prefix) + ); await waitForObjectsLoaded(page); await page.getByRole('button', { name: 'Toggle selection mode' }).click(); await page.getByLabel('Select sub').check(); diff --git a/e2e/storage/tabs.spec.ts b/e2e/storage/tabs.spec.ts new file mode 100644 index 00000000..723665fc --- /dev/null +++ b/e2e/storage/tabs.spec.ts @@ -0,0 +1,355 @@ +import { test, expect } from '@playwright/test'; +import { hasGarageCredentials, requireGarageCredentials } from '../support/garage.js'; +import { waitForHydration } from '../support/helpers.js'; +import { + connectToStorage, + connectAndOpenPrefix, + bucketRoute, + seedStorageTabsState +} from './helpers.js'; + +// ── Tab bar ─────────────────────────────────────────────────────────────────── + +test.describe('Storage — Explorer tab bar', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + test('tab bar is visible when there is only one tab', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await expect(page.getByRole('tablist', { name: 'Explorer tabs' })).toBeVisible(); + }); + + test('add tab via + button shows the tab bar with two tabs', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await expect(tablist).toBeVisible(); + await expect(tablist.getByRole('tab')).toHaveCount(2); + // Newly added tab becomes active + await expect(tablist.getByRole('tab').nth(1)).toHaveAttribute('aria-selected', 'true'); + }); + + test('clicking a tab switches the active tab', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + const tabs = tablist.getByRole('tab'); + + // Second tab is currently active; click the first + await tabs.nth(0).click(); + await expect(tabs.nth(0)).toHaveAttribute('aria-selected', 'true'); + await expect(tabs.nth(1)).toHaveAttribute('aria-selected', 'false'); + }); + + test('tabs retain separate bucket locations', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await page.getByRole('button', { name: 'New Tab' }).click(); + await page.getByRole('link', { name: credentials.bucket, exact: true }).last().click(); + + await expect(tablist.getByRole('tab').nth(1)).toHaveAttribute('title', credentials.bucket); + await tablist.getByRole('tab').nth(0).click(); + await expect(page).toHaveURL( + bucketRoute(new URL(credentials.endpoint).hostname, credentials.bucket) + ); + }); + + test('closing a tab leaves the tab bar visible when one remains', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await expect(tablist.getByRole('tab')).toHaveCount(2); + + // Hover the tab to make the close button visible (it is opacity-0 by default) + const firstTab = tablist.getByRole('tab').nth(0); + await firstTab.hover(); + await firstTab.getByRole('button', { name: 'Close tab' }).click(); + + await expect(tablist).toBeVisible(); + await expect(tablist.getByRole('tab')).toHaveCount(1); + }); + + test('close button is absent when only one tab exists', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await expect(page.getByRole('button', { name: 'Close tab' })).toHaveCount(0); + }); + + test('middle-click on a tab closes it', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await expect(tablist.getByRole('tab')).toHaveCount(2); + + await tablist.getByRole('tab').nth(1).click({ button: 'middle' }); + + await expect(tablist).toBeVisible(); + }); + + test('double-click on a tab starts inline rename', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await tablist.getByRole('tab').nth(0).dblclick(); + + const input = page.getByRole('textbox', { name: 'Rename tab' }); + await expect(input).toBeVisible(); + + await input.fill('My renamed tab'); + await input.press('Enter'); + + await expect(tablist.getByRole('tab').nth(0)).toContainText('My renamed tab'); + }); + + test('Escape cancels rename without changing the label', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + const firstTab = tablist.getByRole('tab').nth(0); + + // The initial label is the bucket name (prefix is empty) + const originalLabel = credentials.bucket; + + await firstTab.dblclick(); + await page.getByRole('textbox', { name: 'Rename tab' }).fill('discarded name'); + await page.keyboard.press('Escape'); + + // Input disappears and the original label is preserved + await expect(page.getByRole('textbox', { name: 'Rename tab' })).not.toBeVisible(); + await expect(firstTab).toHaveAttribute('title', originalLabel); + }); + + test('right-click opens a context menu with Rename and Close options', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await tablist.getByRole('tab').nth(0).click({ button: 'right' }); + + const tabmenu = page.getByRole('menu', { name: 'Tab options' }); + await expect(tabmenu).toBeVisible(); + await expect(tabmenu.getByRole('menuitem', { name: 'Rename tab' })).toBeVisible(); + await expect(tabmenu.getByRole('menuitem', { name: 'Close tab' })).toBeVisible(); + }); + + test('rename via right-click context menu', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await tablist.getByRole('tab').nth(0).click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Rename tab' }).click(); + + const input = page.getByRole('textbox', { name: 'Rename tab' }); + await expect(input).toBeVisible(); + await input.fill('Context menu rename'); + await input.press('Enter'); + + await expect(tablist.getByRole('tab').nth(0)).toContainText('Context menu rename'); + }); + + test('close tab via right-click context menu', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await expect(tablist.getByRole('tab')).toHaveCount(2); + + await tablist.getByRole('tab').nth(0).click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Close tab' }).click(); + + await expect(tablist).toBeVisible(); + await expect(tablist.getByRole('tab')).toHaveCount(1); + }); + + test('New Tab button adds a tab', async ({ page }) => { + const credentials = requireGarageCredentials(); + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + // Tab bar must appear with 2 tabs + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await expect(tablist).toBeVisible(); + await expect(tablist.getByRole('tab')).toHaveCount(2); + }); +}); + +// ── Restore banner ──────────────────────────────────────────────────────────── + +test.describe('Storage — Restore tabs banner', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + test('banner appears when there are 2 or more saved tabs', async ({ page }) => { + const credentials = requireGarageCredentials(); + + await seedStorageTabsState(page, { + tabs: [ + { id: 'tab-a', label: credentials.bucket, bucket: credentials.bucket, prefix: '' }, + { id: 'tab-b', label: 'subfolder', bucket: credentials.bucket, prefix: 'subfolder/' } + ], + activeTabId: 'tab-a' + }); + + await connectToStorage(page, credentials); + await expect(page).toHaveURL('/storage'); + + await expect(page.getByRole('alert')).toBeVisible(); + await expect(page.getByRole('button', { name: 'Restore tabs' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Dismiss' })).toBeVisible(); + }); + + test('banner message includes the saved tab count', async ({ page }) => { + const credentials = requireGarageCredentials(); + + await seedStorageTabsState(page, { + tabs: [ + { id: 'tab-a', label: credentials.bucket, bucket: credentials.bucket, prefix: '' }, + { id: 'tab-b', label: 'folder-1', bucket: credentials.bucket, prefix: 'folder-1/' }, + { id: 'tab-c', label: 'folder-2', bucket: credentials.bucket, prefix: 'folder-2/' } + ], + activeTabId: 'tab-a' + }); + + await connectToStorage(page, credentials); + await expect(page).toHaveURL('/storage'); + + await expect(page.getByRole('alert')).toContainText('3'); + }); + + test('banner does not appear when there is only one saved tab', async ({ page }) => { + const credentials = requireGarageCredentials(); + + await seedStorageTabsState(page, { + tabs: [{ id: 'tab-a', label: credentials.bucket, bucket: credentials.bucket, prefix: '' }], + activeTabId: 'tab-a' + }); + + await connectToStorage(page, credentials); + await expect(page).toHaveURL('/storage'); + + await expect(page.getByRole('button', { name: 'Restore tabs' })).not.toBeVisible(); + }); + + test('Dismiss hides the banner', async ({ page }) => { + const credentials = requireGarageCredentials(); + + await seedStorageTabsState(page, { + tabs: [ + { id: 'tab-a', label: credentials.bucket, bucket: credentials.bucket, prefix: '' }, + { id: 'tab-b', label: 'subfolder', bucket: credentials.bucket, prefix: 'subfolder/' } + ], + activeTabId: 'tab-a' + }); + + await connectToStorage(page, credentials); + await expect(page).toHaveURL('/storage'); + + await page.getByRole('button', { name: 'Dismiss' }).click(); + + await expect(page.getByRole('button', { name: 'Restore tabs' })).not.toBeVisible(); + }); + + test('Dismiss does not clear saved tabs — banner reappears on re-visit', async ({ page }) => { + test.slow(); // navigates to / (Trino editor) which is slow in Firefox + const credentials = requireGarageCredentials(); + + // Step 1: navigate to bucket and add a second tab via natural interaction + await connectAndOpenPrefix(page, credentials); + + await page.getByRole('button', { name: 'New Tab' }).click(); + await expect(page.getByRole('tablist', { name: 'Explorer tabs' }).getByRole('tab')).toHaveCount( + 2 + ); + + // Step 2: navigate back to /storage — banner should appear + await page.goto('/storage'); + await waitForHydration(page); + await expect(page.getByRole('button', { name: 'Restore tabs' })).toBeVisible(); + + // Step 3: dismiss + await page.getByRole('button', { name: 'Dismiss' }).click(); + await expect(page.getByRole('button', { name: 'Restore tabs' })).not.toBeVisible(); + + // Step 4: navigate to dashboard and back — banner must reappear because + // localStorage was not cleared by Dismiss + await page.goto('/'); + await waitForHydration(page); + await page.goto('/storage'); + await waitForHydration(page); + + await expect(page.getByRole('button', { name: 'Restore tabs' })).toBeVisible(); + }); + + test('Restore tabs navigates to the active-tab bucket and loads all tabs', async ({ page }) => { + test.slow(); // page.goto('/storage') in Firefox is slow + const credentials = requireGarageCredentials(); + + // Step 1: navigate to bucket and add a second tab via natural interaction + await connectAndOpenPrefix(page, credentials); + await page.getByRole('button', { name: 'New Tab' }).click(); + await expect(page.getByRole('tablist', { name: 'Explorer tabs' }).getByRole('tab')).toHaveCount( + 2 + ); + + // Step 2: navigate back to /storage — banner appears + await page.goto('/storage'); + await waitForHydration(page); + await expect(page.getByRole('button', { name: 'Restore tabs' })).toBeVisible(); + + // Step 3: click Restore tabs + await page.getByRole('button', { name: 'Restore tabs' }).click(); + + // Should navigate to the bucket route + await expect(page).toHaveURL( + bucketRoute(new URL(credentials.endpoint).hostname, credentials.bucket) + ); + + // Step 4: tab bar must render with 2 restored tabs + const tablist = page.getByRole('tablist', { name: 'Explorer tabs' }); + await expect(tablist).toBeVisible(); + await expect(tablist.getByRole('tab')).toHaveCount(2); + }); +}); diff --git a/e2e/storage/toast.spec.ts b/e2e/storage/toast.spec.ts new file mode 100644 index 00000000..86c76b10 --- /dev/null +++ b/e2e/storage/toast.spec.ts @@ -0,0 +1,57 @@ +import { test, expect } from '@playwright/test'; +import { + createS3Client, + hasGarageCredentials, + requireGarageCredentials +} from '../support/garage.js'; +import { + connectAndOpenPrefix, + deleteKnownKeys, + putTextObject, + rowByName, + uniquePrefix +} from './helpers.js'; + +test.describe('Storage S3 — Toast notifications', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + test('copying a file shows a success toast with a dismiss button', async ({ page }, testInfo) => { + const credentials = requireGarageCredentials(); + const client = createS3Client(credentials); + const prefix = uniquePrefix(testInfo, 'toast-copy'); + const srcFile = `${prefix}toast-test.txt`; + const cleanupKeys = [srcFile]; + + try { + await putTextObject(client, credentials.bucket, srcFile, 'toast test content'); + + await connectAndOpenPrefix(page, credentials, prefix); + + // Copy the file via context menu — triggers a success toast + await rowByName(page, 'toast-test.txt').click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Copy', exact: true }).click(); + await page.waitForTimeout(500); + + // Verify the success toast appears with the correct role + const toast = page.getByRole('alert').filter({ hasText: /copied/i }); + await expect(toast).toBeVisible(); + + // Verify the toast has a Dismiss button + const dismissBtn = toast.getByRole('button', { name: 'Dismiss' }); + await expect(dismissBtn).toBeVisible(); + + // Click Dismiss and verify the toast disappears + await dismissBtn.click(); + await expect(toast).not.toBeVisible(); + } finally { + await deleteKnownKeys(client, credentials.bucket, cleanupKeys); + } + }); +}); diff --git a/e2e/storage/tooltip.spec.ts b/e2e/storage/tooltip.spec.ts new file mode 100644 index 00000000..ebf6673f --- /dev/null +++ b/e2e/storage/tooltip.spec.ts @@ -0,0 +1,38 @@ +import { test, expect } from '@playwright/test'; +import { + createS3Client, + hasGarageCredentials, + requireGarageCredentials +} from '../support/garage.js'; +import { connectAndOpenPrefix } from './helpers.js'; + +test.describe('Storage S3 — Tooltips', () => { + test.use({ locale: 'en-US' }); + + test.beforeEach(() => { + test.skip( + !hasGarageCredentials(), + 'Skipped: no s3-config.json found (requires a running Garage instance)' + ); + }); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + test('hovering over a sidebar bucket name shows a tooltip', async ({ page }, _testInfo) => { + const credentials = requireGarageCredentials(); + createS3Client(credentials); + + await connectAndOpenPrefix(page, credentials, ''); + + // Find the sidebar bucket link for the configured bucket + const bucketLink = page.locator('nav a').filter({ hasText: credentials.bucket }).first(); + await expect(bucketLink).toBeVisible(); + + // Hover over the bucket link to trigger onmouseenter → showTooltip + await bucketLink.hover(); + + // Verify a tooltip element appears with the bucket name + const tooltip = page.getByRole('tooltip'); + await expect(tooltip).toBeVisible(); + await expect(tooltip).toContainText(credentials.bucket); + }); +}); diff --git a/e2e/storage/upload.spec.ts b/e2e/storage/upload.spec.ts index 079f9816..bc91eabc 100644 --- a/e2e/storage/upload.spec.ts +++ b/e2e/storage/upload.spec.ts @@ -82,17 +82,19 @@ test.describe('Storage S3 — Upload', () => { await rowByName(page, textFixture.name).dblclick(); await expect(page.getByRole('heading', { name: textFixture.name })).toBeVisible(); await expect(page.getByText(textFixture.expectedSnippet)).toBeVisible(); - await page.getByRole('button', { name: 'Close' }).last().click(); + await page.getByRole('button', { name: 'Close' }).first().click(); + await expect(page.getByRole('heading', { name: textFixture.name })).not.toBeVisible(); await rowByName(page, csvFixture.name).dblclick(); await expect(page.getByRole('heading', { name: csvFixture.name })).toBeVisible(); await expect(page.getByText(csvFixture.expectedCell)).toBeVisible(); - await page.getByRole('button', { name: 'Close' }).last().click(); + await page.getByRole('button', { name: 'Close' }).first().click(); + await expect(page.getByRole('heading', { name: csvFixture.name })).not.toBeVisible(); await rowByName(page, imageFixture.name).dblclick(); await expect(page.getByRole('heading', { name: imageFixture.name })).toBeVisible(); await expect(page.getByAltText(`Preview of ${imageFixture.name}`)).toBeVisible(); - await page.getByRole('button', { name: 'Close' }).last().click(); + await page.keyboard.press('Escape'); } finally { await deleteKnownKeys(client, credentials.bucket, cleanupKeys); } diff --git a/e2e/support/containers/garage.setup.ts b/e2e/support/containers/garage.setup.ts new file mode 100644 index 00000000..8b206ba0 --- /dev/null +++ b/e2e/support/containers/garage.setup.ts @@ -0,0 +1,83 @@ +import path from 'path'; +import { GenericContainer, type StartedTestContainer, Wait } from 'testcontainers'; +import { createGarageBucketCredentials, createGarageHiddenBucket } from '../garage.js'; + +export async function startGarage(): Promise { + const garageStart = Date.now(); + console.log('Starting Garage S3 testcontainer...'); + const garageContainerBuilder = new GenericContainer( + 'oci.stackable.tech/stackable/dxflrs/garage:v2.3.0' + ) + .withEntrypoint(['/garage']) + .withCommand(['server', '--single-node']) + .withEnvironment({ GARAGE_CONFIG_FILE: '/etc/garage/garage.toml' }) + .withBindMounts([ + { + source: path.resolve('dev/garage/garage.toml'), + target: '/etc/garage/garage.toml', + mode: 'ro' + } + ]) + .withExposedPorts(3900, 3902) + .withStartupTimeout(120_000) + .withWaitStrategy(Wait.forHttp('/health', 3902).forStatusCode(200)); + if (process.env.DOCKER_NETWORK) { + garageContainerBuilder.withNetworkMode(process.env.DOCKER_NETWORK); + } + const garageContainer = await garageContainerBuilder.start(); + console.log(`Garage S3 started in ${Date.now() - garageStart}ms`); + + await setupGarageBucket(garageContainer); + + return garageContainer; +} + +async function setupGarageBucket(garageContainer: StartedTestContainer): Promise { + const garageHost = garageContainer.getHost(); + const garageS3Endpoint = `http://${garageHost}:${garageContainer.getMappedPort(3900)}`; + const garageAdminUrl = `http://${garageHost}:${garageContainer.getMappedPort(3902)}`; + // Admin token is defined in dev/garage/garage.toml. + const garageAdminToken = 'stackable-cockpit-e2e-admin-token'; + + process.env.GARAGE_ADMIN_URL = garageAdminUrl; + process.env.GARAGE_ADMIN_TOKEN = garageAdminToken; + + // Create the test bucket and access key via the Garage admin API. + const bucketStart = Date.now(); + console.log('Creating Garage test bucket and credentials...'); + const credentials = await createGarageBucketCredentials( + { + endpoint: garageS3Endpoint, + region: 'garage', + accessKeyId: '', + secretAccessKey: '', + bucket: 'test-bucket' + }, + { + bucketName: 'test-bucket', + keyName: 'e2e-test-app', + permissions: { owner: true, read: true, write: true } + } + ); + console.log(`Garage setup complete in ${Date.now() - bucketStart}ms`); + + process.env.S3_TEST_ENDPOINT = garageS3Endpoint; + process.env.S3_TEST_REGION = 'garage'; + process.env.S3_TEST_ACCESS_KEY_ID = credentials.accessKeyId; + process.env.S3_TEST_SECRET_ACCESS_KEY = credentials.secretAccessKey; + process.env.S3_TEST_BUCKET = 'test-bucket'; + + // Hidden bucket: no global alias so it does not appear in S3 ListBuckets, + // but the test key has read and write access. + const hiddenBucketId = await createGarageHiddenBucket( + { + endpoint: garageS3Endpoint, + region: 'garage', + accessKeyId: credentials.accessKeyId, + secretAccessKey: credentials.secretAccessKey, + bucket: 'test-bucket' + }, + credentials.accessKeyId + ); + process.env.S3_TEST_HIDDEN_BUCKET_ID = hiddenBucketId; +} diff --git a/e2e/support/containers/postgres.setup.ts b/e2e/support/containers/postgres.setup.ts new file mode 100644 index 00000000..1cc781f0 --- /dev/null +++ b/e2e/support/containers/postgres.setup.ts @@ -0,0 +1,22 @@ +import { PostgreSqlContainer, type StartedPostgreSqlContainer } from '@testcontainers/postgresql'; + +export async function startPostgres(): Promise { + const pgStart = Date.now(); + console.log('Starting PostgreSQL testcontainer...'); + const pgContainerBuilder = new PostgreSqlContainer( + 'oci.stackable.tech/stackable/library/postgres:18.4-alpine3.24' + ).withStartupTimeout(120_000); + if (process.env.DOCKER_NETWORK) { + pgContainerBuilder.withNetworkMode(process.env.DOCKER_NETWORK); + } + const pgContainer = await pgContainerBuilder.start(); + console.log(`PostgreSQL started in ${Date.now() - pgStart}ms`); + + process.env.DATABASE_HOST = pgContainer.getHost(); + process.env.DATABASE_PORT = pgContainer.getPort().toString(); + process.env.DATABASE_NAME = pgContainer.getDatabase(); + process.env.DATABASE_USER = pgContainer.getUsername(); + process.env.DATABASE_PASSWORD = pgContainer.getPassword(); + + return pgContainer; +} diff --git a/e2e/support/db-migrations.setup.ts b/e2e/support/db-migrations.setup.ts new file mode 100644 index 00000000..d660fda8 --- /dev/null +++ b/e2e/support/db-migrations.setup.ts @@ -0,0 +1,17 @@ +import { test as setup } from '@playwright/test'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import { migrate } from 'drizzle-orm/node-postgres/migrator'; +import fs from 'node:fs/promises'; +import path from 'path'; + +const stateFile = path.resolve('.playwright/postgres-state.json'); + +setup('run database migrations', async () => { + const raw = await fs.readFile(stateFile, 'utf-8'); + const { connectionUri } = JSON.parse(raw) as { connectionUri: string }; + + const db = drizzle(connectionUri); + await migrate(db, { + migrationsFolder: path.resolve('src/lib/server/migrations') + }); +}); diff --git a/e2e/support/garage.ts b/e2e/support/garage.ts index 3d4142b0..e778a4bc 100644 --- a/e2e/support/garage.ts +++ b/e2e/support/garage.ts @@ -37,6 +37,7 @@ function readString(value: unknown, keys: string[]): string | null { } for (const key of keys) { + // eslint-disable-next-line security/detect-object-injection const candidate = record[key]; if (typeof candidate === 'string' && candidate.length > 0) { return candidate; @@ -53,6 +54,7 @@ function readStringArray(value: unknown, keys: string[]): string[] { } for (const key of keys) { + // eslint-disable-next-line security/detect-object-injection const candidate = record[key]; if (Array.isArray(candidate)) { return candidate.filter((item): item is string => typeof item === 'string'); @@ -73,6 +75,7 @@ function extractAdminList(value: unknown): JsonRecord[] { } for (const key of ADMIN_LIST_KEYS) { + // eslint-disable-next-line security/detect-object-injection const candidate = record[key]; if (Array.isArray(candidate)) { return candidate @@ -285,3 +288,46 @@ export async function createGarageBucketCredentials( bucket: options.bucketName }; } + +/** + * Creates a bucket with no global alias (so it is absent from S3 ListBuckets + * responses) and grants the given access key read and write — but not owner — + * access. Returns the Garage bucket ID, which is the only handle for the + * bucket when it has no alias. + */ +export async function createGarageHiddenBucket( + baseCredentials: GarageCredentials, + accessKeyId: string +): Promise { + const created = await adminPost('/v2/CreateBucket', {}); + const bucketId = readString(created, ['id', 'bucketId', 'bucket_id']); + + if (!bucketId) { + throw new Error('Garage hidden bucket was created without an ID'); + } + + await adminPost('/v2/AllowBucketKey', { + bucketId, + accessKeyId, + permissions: { owner: false, read: true, write: true } + }); + + return bucketId; +} + +export function hasHiddenBucketId(): boolean { + return Boolean(process.env.S3_TEST_HIDDEN_BUCKET_ID); +} + +export function requireHiddenBucketId(): string { + const id = process.env.S3_TEST_HIDDEN_BUCKET_ID; + + if (!id) { + throw new Error( + 'Hidden bucket ID is not available — S3_TEST_HIDDEN_BUCKET_ID is not set. ' + + 'Run the dev setup or ensure init-garage-s3.sh has run.' + ); + } + + return id; +} diff --git a/e2e/support/global-setup.ts b/e2e/support/global-setup.ts index 3754ac1b..2f48ae48 100644 --- a/e2e/support/global-setup.ts +++ b/e2e/support/global-setup.ts @@ -1,35 +1,47 @@ -import fs from 'node:fs'; +import fsPromises from 'node:fs/promises'; import path from 'path'; +import type { StartedPostgreSqlContainer } from '@testcontainers/postgresql'; +import type { StartedTestContainer } from 'testcontainers'; +import { startPostgres } from './containers/postgres.setup.js'; +import { startGarage } from './containers/garage.setup.js'; + +const stateFile = path.resolve('.playwright/postgres-state.json'); + +let pgContainer: StartedPostgreSqlContainer; +let garageContainer: StartedTestContainer; export default async function globalSetup() { process.loadEnvFile(path.join(import.meta.dirname, '../..', '.env.test')); - // Optionally load S3 credentials written by the Garage setup step in CI. - // When present, storage S3 tests run; when absent, they are skipped. - // The admin URL/token from s3-config.json override .env.test values so that - // the permissions tests connect to the correct Garage admin port in CI. - const s3ConfigPath = path.join(import.meta.dirname, '../..', 's3-config.json'); - if (fs.existsSync(s3ConfigPath)) { - const raw = fs.readFileSync(s3ConfigPath, 'utf-8'); - const cfg = JSON.parse(raw) as { - awsEndpoint: string; - awsRegion: string; - awsAccessKeyId: string; - awsSecretAccessKey: string; - bucket: string; - garageAdminUrl?: string; - garageAdminToken?: string; - }; - process.env.S3_TEST_ENDPOINT = cfg.awsEndpoint; - process.env.S3_TEST_REGION = cfg.awsRegion; - process.env.S3_TEST_ACCESS_KEY_ID = cfg.awsAccessKeyId; - process.env.S3_TEST_SECRET_ACCESS_KEY = cfg.awsSecretAccessKey; - process.env.S3_TEST_BUCKET = cfg.bucket; - if (cfg.garageAdminUrl) { - process.env.GARAGE_ADMIN_URL = cfg.garageAdminUrl; - } - if (cfg.garageAdminToken) { - process.env.GARAGE_ADMIN_TOKEN = cfg.garageAdminToken; - } + // When invoked via `npm run test:e2e`, the run-e2e.ts wrapper starts + // containers before spawning Playwright so that the webServer subprocess + // inherits DATABASE_* and S3_* env vars. Nothing to do here in that case. + if (process.env.TESTCONTAINERS_STARTED === 'true') { + return; } + + // Fallback for direct `playwright test` invocations (e.g. from the IDE). + // Note: in this path the webServer process is already running before + // containers are ready, so connection errors are possible unless + // reuseExistingServer is true and an existing server is already up. + pgContainer = await startPostgres(); + garageContainer = await startGarage(); + + await fsPromises.mkdir(path.dirname(stateFile), { recursive: true }); + await fsPromises.writeFile( + stateFile, + JSON.stringify({ + connectionUri: pgContainer.getConnectionUri() + }), + 'utf-8' + ); + + // Return a teardown function — runs in the main process after all tests, + // so we can call .stop() directly instead of shelling out to Docker CLI. + return async () => { + console.log('Tearing down testcontainers...'); + await Promise.allSettled([garageContainer.stop(), pgContainer.stop()]); + await fsPromises.rm(stateFile, { force: true }); + console.log('Testcontainers stopped.'); + }; } diff --git a/e2e/support/run-e2e.ts b/e2e/support/run-e2e.ts new file mode 100644 index 00000000..3998d3fa --- /dev/null +++ b/e2e/support/run-e2e.ts @@ -0,0 +1,67 @@ +/** + * Wrapper script that starts testcontainers BEFORE launching Playwright. + * + * Playwright's startup order is: + * 1. webServer plugin processes are spawned + * 2. globalSetup runs + * 3. Tests run + * + * This means env vars set in globalSetup are not inherited by the webServer + * subprocess. By starting the containers here — before `playwright test` is + * spawned — the child process inherits DATABASE_* and S3_* env vars and the + * SvelteKit app server can connect to the database on first query. + */ + +import { spawn } from 'node:child_process'; +import fsPromises from 'node:fs/promises'; +import path from 'node:path'; +import { startPostgres } from './containers/postgres.setup.js'; +import { startGarage } from './containers/garage.setup.js'; + +process.loadEnvFile(path.join(import.meta.dirname, '../..', '.env.test')); + +const stateFile = path.resolve('.playwright/postgres-state.json'); + +async function main() { + console.log('Starting test containers...'); + const [pgContainer, garageContainer] = await Promise.all([startPostgres(), startGarage()]); + + await fsPromises.mkdir(path.dirname(stateFile), { recursive: true }); + await fsPromises.writeFile( + stateFile, + JSON.stringify({ connectionUri: pgContainer.getConnectionUri() }), + 'utf-8' + ); + + // Signal to globalSetup that containers are already running so it skips + // the fallback startup path. + process.env.TESTCONTAINERS_STARTED = 'true'; + + let exitCode = 0; + try { + exitCode = await runPlaywright(process.argv.slice(2)); + } finally { + console.log('Tearing down testcontainers...'); + await Promise.allSettled([garageContainer.stop(), pgContainer.stop()]); + await fsPromises.rm(stateFile, { force: true }); + console.log('Testcontainers stopped.'); + } + + process.exit(exitCode); +} + +function runPlaywright(args: string[]): Promise { + return new Promise((resolve, reject) => { + const pw = spawn('npx', ['playwright', 'test', ...args], { + stdio: 'inherit', + env: process.env + }); + pw.on('error', reject); + pw.on('close', (code) => resolve(code ?? 0)); + }); +} + +main().catch((err) => { + console.error('Failed to run E2E tests:', err); + process.exit(1); +}); diff --git a/e2e/trino/trino-tabs.spec.ts b/e2e/trino/trino-tabs.spec.ts index 1dd01b26..6adb1f71 100644 --- a/e2e/trino/trino-tabs.spec.ts +++ b/e2e/trino/trino-tabs.spec.ts @@ -59,6 +59,30 @@ test.describe('Trino editor tabs', () => { await expect(tabs).toHaveCount(1); }); + test('close non-active tab removes it and preserves active tab', async ({ page }) => { + await setTabState(page, [{ sql: 'SELECT 1' }, { sql: 'SELECT 2' }]); + await page.goto('/trino'); + await waitForHydration(page); + + const tabs = page.locator('[role="tab"]'); + await expect(tabs).toHaveCount(2); + + // Switch to the second tab to make it active + await tabs.nth(1).click(); + await expect(tabs.nth(1)).toHaveAttribute('aria-selected', 'true'); + + // Close the first (non-active) tab + const closeBtn = tabs + .nth(0) + .locator('..') + .getByRole('button', { name: /Close tab/ }); + await closeBtn.click(); + + // Only one tab remains with default label — it should still be active + await expect(page.locator('[role="tab"]')).toHaveCount(1); + await expect(page.locator('[role="tab"]').nth(0)).toHaveAttribute('aria-selected', 'true'); + }); + test('cannot close last remaining tab', async ({ page }) => { // With only one tab, close button should not be visible. const tabs = page.locator('[role="tab"]'); @@ -112,6 +136,8 @@ test.describe('Trino editor tabs', () => { await setTabState(page, [{ sql: 'SELECT id, name FROM users' }, { sql: 'SELECT 2' }]); await page.goto('/trino'); await waitForHydration(page); + // Wait for Monaco editor to be fully initialised. + await page.locator('[data-ready]').first().waitFor({ timeout: 15_000 }); // Focus editor and run query on first tab. await page.locator('.monaco-editor').first().click(); diff --git a/eslint.config.js b/eslint.config.js index 1e6f8cb6..1c735d51 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -49,7 +49,23 @@ export default ts.config( } }, rules: { - 'better-tailwindcss/no-unknown-classes': ['warn', { detectComponentClasses: true }] + 'better-tailwindcss/no-unknown-classes': [ + 'warn', + { + detectComponentClasses: true, + ignore: [ + 'dropdown-content', + 'dropdown-open', + 'swap-on', + 'swap-off', + 'label-text', + 'menu-disabled', + 'tab-active', + 'tab-strip', + 'preview-scroll' + ] + } + ] } } ); diff --git a/messages/de.json b/messages/de.json index 8b0bc0b1..d6fde8c8 100644 --- a/messages/de.json +++ b/messages/de.json @@ -1,5 +1,7 @@ { "$schema": "https://inlang.com/schema/inlang-message-format", + "action_close": "Schließen", + "action_dismiss": "Schließen", "dashboard_welcome": "Willkommen zurück", "dashboard_subtitle": "Stackable Unified Data Platform – Übersicht", "dashboard_services": "Dienste", @@ -21,6 +23,7 @@ "nav_badge_soon": "Bald", "sidebar_label": "Seitenleiste", "sidebar_nav_label": "Hauptnavigation", + "navigation_loading": "Wird geladen…", "sidebar_close_nav": "Navigation schließen", "sidebar_expand": "Seitenleiste ausklappen", "sidebar_collapse": "Seitenleiste einklappen", @@ -145,13 +148,33 @@ "storage_connect_secret_key": "Geheimer Schlüssel", "storage_connect_submit": "Verbinden", "storage_connect_reconnecting": "Verbindung zum Speicher wird wiederhergestellt…", + "storage_connect_timeout": "Zeitüberschreitung der Verbindung. Das Speicher-Backend hat nicht geantwortet.", + "storage_connect_cancel": "Abbrechen", "storage_connect_error": "Verbindung fehlgeschlagen — Endpunkt und Zugangsdaten prüfen.", + "storage_connect_error_unreachable": "Verbindung zum ausgewählten Speicher nicht möglich — der Endpunkt ist möglicherweise nicht erreichbar.", + "storage_connect_error_access_denied": "Zugriff verweigert — Zugangsdaten prüfen.", + "storage_connect_error_not_found": "Speicher-Backend nicht gefunden — Endpunkt prüfen.", + "storage_connect_error_server_error": "Das Speicher-Backend hat einen Fehler gemeldet — Endpunkt und Zugangsdaten prüfen.", + "storage_connect_error_network": "Speicher-Backend nicht erreichbar — Host und Port prüfen.", + "storage_connect_error_hdfs": "HDFS-Verbindungen werden noch nicht unterstützt", "storage_connect_saved": "Gespeicherte Verbindungen", "storage_connect_no_saved": "Noch keine gespeicherten Verbindungen", "storage_connect_forget": "Löschen", "storage_connect_forget_confirm": "{endpoint} aus den gespeicherten Verbindungen löschen?", "storage_connect_forget_cancel": "Abbrechen", "storage_connect_forget_label": "Verbindung zu {endpoint} löschen", + "storage_connect_name": "Verbindungsname", + "storage_connect_name_placeholder": "z.B. Primäres S3", + "storage_connect_additional_buckets": "Weitere Buckets", + "storage_connect_additional_buckets_hint": "Bucket-Namen, die nicht von ListBuckets zurückgegeben werden, einer pro Zeile", + "storage_connect_duplicate_warning": "Doppelte Zugangsdaten erkannt", + "storage_connect_delete_label": "Verbindung {name} löschen", + "storage_connect_delete_confirm_title": "\"{name}\" löschen?", + "storage_connect_delete_confirm_message": "Die gespeicherten Zugangsdaten werden dauerhaft entfernt.", + "storage_connect_delete_confirm_button": "Löschen", + "storage_connect_delete_cancel": "Abbrechen", + "storage_connect_add_new": "Neue Verbindung hinzufügen", + "storage_connect_testing": "Verbindung wird getestet…", "storage_connect_copy": "Kopieren", "storage_connect_copied": "Kopiert", "storage_connect_copy_all": "Alles kopieren", @@ -167,7 +190,7 @@ "storage_connections_empty": "Noch keine gespeicherten Verbindungen.", "storage_connections_edit": "Bearbeiten", "storage_connections_delete": "Löschen", - "storage_connections_delete_confirm": "\u201e{label}\u201c aus den gespeicherten Verbindungen entfernen? Dies kann nicht rückgängig gemacht werden.", + "storage_connections_delete_confirm": "\"{label}\" aus den gespeicherten Verbindungen entfernen? Dies kann nicht rückgängig gemacht werden.", "storage_connections_delete_cancel": "Abbrechen", "storage_connections_delete_confirm_button": "Löschen", "storage_connection_edit_title": "Verbindung bearbeiten", @@ -193,6 +216,16 @@ "storage_buckets_subtitle": "Durchsuchen und verwalten Sie Ihre gespeicherten Objekte.", "storage_view_all_buckets": "Alle Buckets anzeigen", "storage_buckets_empty": "Keine Buckets gefunden", + "storage_add_bucket": "Bucket hinzufügen", + "storage_add_bucket_title": "Mit einem Bucket verbinden", + "storage_add_bucket_subtitle": "Geben Sie den Namen eines Buckets ein, auf den Sie Zugriff haben.", + "storage_add_bucket_name_label": "Bucket-Name", + "storage_add_bucket_name_placeholder": "mein-bucket", + "storage_add_bucket_submit": "Verbinden", + "storage_add_bucket_cancel": "Abbrechen", + "storage_add_bucket_error_access_denied": "Zugriff verweigert — Sie haben keine Berechtigung, diesen Bucket zu lesen.", + "storage_add_bucket_error_not_found": "Bucket nicht gefunden — überprüfen Sie den Namen und versuchen Sie es erneut.", + "storage_add_bucket_error_unknown": "Verbindung zum Bucket fehlgeschlagen — überprüfen Sie den Namen und versuchen Sie es erneut.", "storage_bucket_empty": "Dieser Bucket ist leer", "storage_folder": "Ordner", "storage_folders": "Ordner", @@ -223,6 +256,7 @@ "storage_paste_plural": "{count} Elemente einfügen", "storage_selected": "{count} ausgewählt", "storage_action_preview": "Vorschau", + "storage_action_actions_for": "Aktionen für {name}", "storage_action_refresh": "Aktualisieren", "storage_action_preview_no_selection": "Keine Datei für die Vorschau ausgewählt.", "storage_action_download_no_selection": "Keine Datei für den Download ausgewählt.", @@ -234,10 +268,14 @@ "storage_action_delete": "Löschen", "storage_action_paste": "Einfügen", "storage_action_pin": "Ort anheften", + "storage_action_details": "Details", "storage_action_unpin": "Loslösen", "storage_action_copy_filename": "Dateiname kopieren", "storage_action_copy_filename_success": "Dateiname in die Zwischenablage kopiert.", "storage_action_copy_filename_error": "Dateiname konnte nicht in die Zwischenablage kopiert werden.", + "storage_action_copy_directory_name": "Verzeichnisnamen kopieren", + "storage_action_copy_directory_name_success": "Verzeichnisname in die Zwischenablage kopiert.", + "storage_action_copy_directory_name_error": "Verzeichnisname konnte nicht in die Zwischenablage kopiert werden.", "storage_action_copy_path": "Pfad kopieren", "storage_action_copy_path_success": "Pfad in die Zwischenablage kopiert.", "storage_action_copy_path_error": "Pfad konnte nicht in die Zwischenablage kopiert werden.", @@ -260,10 +298,11 @@ "storage_parent_dir": "Übergeordnetes Verzeichnis", "storage_loading": "Wird geladen…", "storage_breadcrumb_more": "Weitere Ordner", + "storage_error_breadcrumb": "Brotkrumen-Navigation", "storage_error_title": "Speicherfehler", - "storage_error_access_denied": "Sie haben keine Berechtigung, auf den Bucket \u201e{bucket}\u201c zuzugreifen.", - "storage_error_not_found": "Der Bucket \u201e{bucket}\u201c existiert nicht.", - "storage_error_storage_error": "Beim Zugriff auf den Bucket \u201e{bucket}\u201c ist ein Fehler aufgetreten.", + "storage_error_access_denied": "Sie haben keine Berechtigung, auf den Bucket „{bucket}“ zuzugreifen.", + "storage_error_not_found": "Der Bucket „{bucket}“ existiert nicht.", + "storage_error_storage_error": "Beim Zugriff auf den Bucket „{bucket}“ ist ein Fehler aufgetreten.", "storage_error_back_to_storage": "Zurück zum Speicher", "storage_error_go_back": "Zurück", "storage_download_error_title": "Download fehlgeschlagen", @@ -273,7 +312,7 @@ "storage_download_error_server_error": "Beim Herunterladen der Datei ist ein Serverfehler aufgetreten. Bitte versuchen Sie es erneut.", "storage_download_error_unknown": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut.", "storage_download_dismiss": "Schließen", - "storage_delete_confirm_title_one": "\u201e{name}\u201c löschen?", + "storage_delete_confirm_title_one": "„{name}“ löschen?", "storage_delete_confirm_title_many": "{count} Elemente löschen?", "storage_delete_confirm_message": "Diese Aktion kann nicht rückgängig gemacht werden.", "storage_delete_dir_warning_heading": "Alle Inhalte werden dauerhaft gelöscht", @@ -320,57 +359,317 @@ "storage_preview_image_alt": "Vorschau von {name}", "storage_preview_csv_columns": "{count} weitere Spalten", "storage_preview_csv_rows": "Erste {count} Zeilen werden angezeigt", + "storage_preview_csv_rows_complete": "Alle {count} Zeilen werden angezeigt", "storage_preview_parquet_rows": "Erste {count} von {total} Zeilen werden angezeigt (Parquet)", + "storage_preview_infinite_scroll_disabled": "Dies ist das Ende der Vorschau. Laden Sie die vollständige Datei herunter oder bitten Sie den Administrator, das unendliche Scrollen zu aktivieren, um weitere Zeilen in dieser Vorschau zu laden.", "storage_preview_pdf_too_large": "PDF ist zu groß für die Inline-Vorschau.", "storage_preview_image_too_large": "Bild ist zu groß für die Anzeige.", "storage_preview_image_too_large_desc": "Die Datei überschreitet die maximale Vorschaugröße. Laden Sie die vollständige Datei herunter, um sie anzuzeigen.", "storage_preview_maximise": "Maximieren", "storage_preview_restore": "Wiederherstellen", + "storage_editor_save": "Speichern", + "storage_editor_saving": "Speichern…", + "storage_editor_saved": "Gespeichert", + "storage_editor_unsaved_title": "Ungespeicherte Änderungen", + "storage_editor_unsaved_desc": "Sie haben ungespeicherte Änderungen. Was möchten Sie tun?", + "storage_editor_save_and_close": "Speichern und schließen", + "storage_editor_discard": "Verwerfen", + "storage_editor_cancel": "Abbrechen", + "storage_editor_error": "Datei konnte nicht gespeichert werden.", + "storage_editor_too_large": "Datei zu groß zum Speichern. Die maximal bearbeitbare Dateigröße beträgt {limit}.", + "storage_editor_too_large_badge": "Schreibgeschützt: überschreitet {limit}", "storage_context_menu_actions": "Aktionen", "storage_action_upload": "Hochladen", "storage_upload_title": "Hochladen", "storage_upload_drop_prompt": "Dateien oder Ordner hier ablegen oder klicken zum Durchsuchen", - "storage_upload_select_files": "Dateien ausw\u00e4hlen", - "storage_upload_select_folder": "Ordner ausw\u00e4hlen", - "storage_upload_selected": "Ausgew\u00e4hlt: {name}", + "storage_upload_select_files": "Dateien auswählen", + "storage_upload_select_folder": "Ordner auswählen", + "storage_upload_selected": "Ausgewählt: {name}", "storage_upload_to_prefix": "Hochladen nach: {prefix}", "storage_upload_total_size": "Gesamt: {size}", "storage_upload_start": "Hochladen", - "storage_upload_checking": "Auf Konflikte pr\u00fcfen\u2026", + "storage_upload_checking": "Auf Konflikte prüfen…", "storage_upload_conflicts_title": "Dateien bereits vorhanden", "storage_upload_conflicts_desc": "Wählen Sie für jede Konfliktdatei eine Aktion.", "storage_upload_skip_all": "Alle überspringen", "storage_upload_replace_all": "Alle ersetzen", "storage_upload_resolution_replace": "Ersetzen", - "storage_upload_resolution_skip": "\u00dcberspringen", + "storage_upload_resolution_skip": "Überspringen", "storage_upload_resolution_rename": "Umbenennen", "storage_upload_rename_label": "Neuer Dateiname", - "storage_upload_rename_same_name_error": "Bitte geben Sie einen anderen Namen ein oder w\u00e4hlen Sie Ersetzen bzw. \u00dcberspringen.", - "storage_upload_rename_confirm_action": "Namen best\u00e4tigen", - "storage_upload_rename_taken": "Dieser Name existiert bereits an diesem Speicherort. Bitte w\u00e4hlen Sie einen anderen Namen.", - "storage_upload_uploading": "Wird hochgeladen\u2026 {pct}%", + "storage_upload_rename_same_name_error": "Bitte geben Sie einen anderen Namen ein oder wählen Sie Ersetzen bzw. Überspringen.", + "storage_upload_rename_confirm_action": "Namen bestätigen", + "storage_upload_rename_taken": "Dieser Name existiert bereits an diesem Speicherort. Bitte wählen Sie einen anderen Namen.", + "storage_upload_uploading": "Wird hochgeladen… {pct}%", "storage_upload_status_queued": "ausstehend", "storage_upload_status_done": "fertig", - "storage_upload_status_skipped": "\u00fcbersprungen", + "storage_upload_status_skipped": "übersprungen", "storage_upload_status_failed": "fehlgeschlagen", "storage_upload_complete_title": "Upload abgeschlossen", - "storage_upload_complete_summary": "{uploaded} hochgeladen \u00b7 {skipped} \u00fcbersprungen \u00b7 {failed} fehlgeschlagen", + "storage_upload_complete_summary": "{uploaded} hochgeladen · {skipped} übersprungen · {failed} fehlgeschlagen", "storage_upload_done": "Fertig", "storage_upload_success": "Datei erfolgreich hochgeladen.", "storage_upload_error_not_connected": "Keine Speicherverbindung konfiguriert. Bitte verbinden Sie sich zuerst.", "storage_upload_error_access_denied": "Zugriff verweigert. Sie haben keine Berechtigung, hier hochzuladen.", "storage_upload_error_no_such_bucket": "Bucket nicht gefunden.", - "storage_upload_error_invalid_part": "Upload fehlgeschlagen (Datenintegrit\u00e4tsfehler). Bitte erneut versuchen.", + "storage_upload_error_invalid_part": "Upload fehlgeschlagen (Datenintegritätsfehler). Bitte erneut versuchen.", "storage_upload_error_server_error": "Serverfehler aufgetreten. Bitte erneut versuchen.", "storage_upload_error_unknown": "Unerwarteter Fehler. Bitte erneut versuchen.", "storage_upload_overwrite_title": "Datei bereits vorhanden", - "storage_upload_overwrite_message": "Ein Objekt namens \u201e{name}\u201c ist bereits vorhanden. Was m\u00f6chten Sie tun?", + "storage_upload_overwrite_message": "Ein Objekt namens „{name}“ ist bereits vorhanden. Was möchten Sie tun?", "storage_upload_overwrite_replace": "Ersetzen", "storage_upload_overwrite_cancel": "Abbrechen", "storage_upload_overwrite_rename": "Umbenennen", "storage_upload_rename_confirm": "Mit diesem Namen hochladen", "storage_upload_retry": "Erneut versuchen", - "storage_upload_close": "Schlie\u00dfen", + "storage_upload_close": "Schließen", + "storage_action_create": "Erstellen", + "storage_create_file": "Neue Textdatei", + "storage_create_folder": "Neues Verzeichnis", + "storage_create_name": "Name", + "storage_create_placeholder": "Namen eingeben…", + "storage_create_confirm": "Erstellen", + "storage_create_cancel": "Abbrechen", + "storage_create_error": "{name} konnte nicht erstellt werden", + "storage_tab_new": "Neuer Tab", + "storage_tab_close": "Tab schließen", + "storage_tab_rename": "Tab umbenennen", + "storage_tab_list": "Explorer-Tabs", + "storage_tab_context_menu": "Tab-Optionen", + "storage_restore_tabs_message": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "Sie haben 1 gespeicherten Tab aus Ihrer letzten Sitzung.", + "countPlural=other": "Sie haben {count} gespeicherte Tabs aus Ihrer letzten Sitzung." + } + } + ], + "storage_restore_tabs_action": "Tabs wiederherstellen", + "storage_preview_parquet_tab_aria": "Parquet-Vorschau-Registerkarten", + "storage_preview_parquet_tab_metadata": "Metadaten", + "storage_preview_parquet_tab_data": "Daten", + "storage_preview_parquet_blocked_title": "Vorschau blockiert", + "storage_preview_parquet_blocked_desc": "Diese Parquet-Datei verwendet einen Kompressionstyp, der vom Administrator deaktiviert wurde. Wenden Sie sich an Ihren Administrator, wenn Sie dies für ein Problem halten.", + "storage_preview_parquet_overview": "Übersicht", + "storage_preview_parquet_file_size": "Dateigröße", + "storage_preview_parquet_total_rows": "Zeilen gesamt", + "storage_preview_parquet_total_columns": "Spalten gesamt", + "storage_preview_parquet_version": "Version", + "storage_preview_parquet_created_by": "Erstellt von", + "storage_preview_parquet_schema": "Schema", + "storage_preview_parquet_column": "Spalte", + "storage_preview_parquet_type": "Typ", + "storage_preview_parquet_compression_indexes": "Kompression & Indexe", + "storage_preview_parquet_row_groups": "Zeilengruppen", + "storage_preview_parquet_row_group": "Gruppe", + "storage_preview_parquet_offset_index": "Offset-Index", + "storage_preview_parquet_column_index": "Spalten-Index", + "storage_preview_parquet_available": "Verfügbar", + "storage_preview_parquet_missing": "Fehlt", + "storage_preview_parquet_none": "Keine", + "storage_preview_parquet_compression": "Kompression", + "storage_preview_parquet_uncompressed": "Unkomprimiert", + "storage_preview_parquet_compressed": "Komprimiert", + "storage_preview_parquet_size": "Größe", + "storage_preview_parquet_statistics": "Statistiken", + "storage_preview_parquet_min": "Min", + "storage_preview_parquet_max": "Max", + "storage_preview_parquet_null_count": "Null-Anzahl", + "storage_preview_parquet_distinct_count": "Distinct-Anzahl", + "storage_preview_parquet_not_stored": "Nicht gespeichert", + "storage_preview_parquet_arrow_schema": "Arrow-Schema", + "storage_preview_parquet_arrow_schema_present": "Eingebettetes Arrow-Schema ({size})", + "storage_preview_parquet_uniform": "einheitlich", + "storage_archive_open_error": "Archiv konnte nicht geöffnet werden. Das Format wird möglicherweise nicht unterstützt oder das Archiv ist beschädigt.", + "storage_archive_too_large": "Archiv ist zu groß für die Vorschau.", + "storage_archive_exit": "Archiv verlassen", + "storage_details_title": "Details", + "storage_details_file_title": "Datei-Details", + "storage_details_folder_title": "Verzeichnis-Details", + "storage_details_bucket_title": "Bucket-Details", + "storage_details_close": "Schließen", + "storage_details_maximise": "Maximieren", + "storage_details_restore": "Wiederherstellen", + "storage_details_property": "Eigenschaft", + "storage_details_value": "Wert", + "storage_details_name": "Name", + "storage_details_size": "Größe", + "storage_details_last_modified": "Zuletzt geändert", + "storage_details_content_type": "Inhaltstyp", + "storage_details_etag": "ETag", + "storage_details_version_id": "Version-ID", + "storage_details_storage_class": "Speicherklasse", + "storage_details_is_delete_marker": "Löschmarkierung", + "storage_details_yes": "Ja", + "storage_details_no": "Nein", + "storage_details_calculate_size": "Verzeichnisgröße berechnen", + "storage_details_calculating": "Wird berechnet…", + "storage_details_calculating_desc": "Alle Objekte in diesem Verzeichnis werden aufgelistet…", + "storage_details_keys_found": "{count} Objekte gefunden", + "storage_details_file_count": "{count} Dateien", + "storage_details_folder_count": "{count} Ordner", + "storage_details_total_size": "Gesamtgröße", + "storage_details_tree_visualization": "Größenverteilung", + "storage_details_versioning": "Versionierung", + "storage_details_versioning_enabled": "Aktiviert", + "storage_details_versioning_suspended": "Ausgesetzt", + "storage_details_versioning_disabled": "Deaktiviert", + "storage_details_lifecycle_rules": "Lebenszyklus-Regeln", + "storage_details_lifecycle_rule_id": "Regel-ID", + "storage_details_lifecycle_status": "Status", + "storage_details_lifecycle_filter": "Filter", + "storage_details_lifecycle_expiration": "Ablauf", + "storage_details_lifecycle_noncurrent_expiration": "Ablauf nicht aktueller Versionen", + "storage_details_lifecycle_transition": "Übergang", + "storage_details_lifecycle_days": "{days} Tage", + "storage_details_lifecycle_abort_mpu": "Abbr. unvollst. Uploads", + "storage_details_lifecycle_days_after_initiation": "{days} T. nach Initiierung", + "storage_details_lifecycle_noncurrent_transition": "Übergang inakt. Versionen", + "storage_details_lifecycle_transition_to": "→ {storageClass}", + "storage_details_lifecycle_prefix_filter": "Präfix: {prefix}", + "storage_details_lifecycle_all_objects": "Alle Objekte", + "storage_details_lifecycle_no_rules": "Keine Lebenszyklus-Regeln konfiguriert", + "storage_details_tags": "Tags", + "storage_details_no_tags": "Keine Tags", + "storage_details_custom_metadata": "Benutzerdefinierte Metadaten", + "storage_details_error_not_connected": "Keine Speicherverbindung konfiguriert", + "storage_details_error_fetch_file": "Dateidetails konnten nicht abgerufen werden ({status})", + "storage_details_error_fetch_bucket": "Bucket-Details konnten nicht abgerufen werden ({status})", + "storage_details_error_fetch_dir_meta": "Verzeichnismetadaten konnten nicht abgerufen werden ({status})", + "storage_details_error_calc_size": "Verzeichnisgröße konnte nicht berechnet werden ({status})", + "storage_details_error_unknown": "Unbekannter Fehler", + "storage_details_error_no_body": "Kein Antworttext", + "storage_details_unnamed_rule": "(unbenannt)", + "storage_details_treemap_aria": "Treemap-Visualisierung der Verzeichnisgrößenverteilung", + "storage_details_treemap_more": "{count} weitere", + "storage_details_copy_dir_name": "Verzeichnisnamen kopieren", + "storage_details_copy_file_name": "Dateinamen kopieren", + "storage_details_copy_full_path": "Vollständigen Pfad kopieren", + "storage_details_tab_overview": "Übersicht", + "storage_details_tab_composition": "Größenverteilung", + "storage_details_tab_contents": "Inhalte", + "storage_details_tab_lifecycle": "Lebenszyklus", + "storage_details_file_path": "Pfad", + "storage_details_bucket_name": "Bucket", + "storage_details_owner": "Besitzer", + "storage_details_permissions": "Berechtigungen", + "storage_details_depth": "Tiefe", + "storage_details_marker_exists": "Ordner-Marker", + "storage_details_marker_none": "Kein Ordner-Marker-Objekt", + "storage_details_encryption": "Verschlüsselung", + "storage_details_object_lock": "Objektsperre", + "storage_details_object_lock_mode": "Sperrmodus", + "storage_details_object_lock_until": "Aufbewahren bis", + "storage_action_cut_success": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 Element ausgeschnitten", + "countPlural=other": "{count} Elemente ausgeschnitten" + } + } + ], + "storage_action_copy_success": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 Element kopiert", + "countPlural=other": "{count} Elemente kopiert" + } + } + ], + "storage_action_paste_success": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 Element eingefügt", + "countPlural=other": "{count} Elemente eingefügt" + } + } + ], + "storage_action_paste_error": "Elemente konnten nicht eingefügt werden. Bitte versuchen Sie es erneut.", + "storage_action_paste_partial": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 Element konnte nicht eingefügt werden.", + "countPlural=other": "{count} Elemente konnten nicht eingefügt werden." + } + } + ], + "storage_action_paste_error_source_not_found": "Einfügen fehlgeschlagen — die Quell-Elemente wurden möglicherweise gelöscht oder verschoben.", + "storage_action_paste_archive_error": "Einfügen innerhalb eines Archivs nicht möglich.", + "storage_action_move_success": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 Element verschoben", + "countPlural=other": "{count} Elemente verschoben" + } + } + ], + "storage_action_move_partial": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 Element konnte nicht verschoben werden.", + "countPlural=other": "{count} Elemente konnten nicht verschoben werden." + } + } + ], + "storage_action_move_error": "Elemente konnten nicht verschoben werden. Bitte versuchen Sie es erneut.", + "storage_action_move_error_not_connected": "Keine Speicherverbindung konfiguriert. Bitte verbinden Sie sich zuerst.", + "storage_action_move_error_access_denied": "Zugriff verweigert. Sie haben keine Berechtigung zum Verschieben.", + "storage_move_confirm_title": "Elemente verschieben", + "storage_move_confirm_body": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 Element nach \"{destination}\" verschieben?", + "countPlural=other": "{count} Elemente nach \"{destination}\" verschieben?" + } + } + ], + "storage_move_confirm_label": "Verschieben", + "storage_move_confirm_cancel": "Abbrechen", + "storage_move_confirm_more": "+{count} mehr", + "storage_move_confirm_total_size": "Gesamt: {size}", + "storage_operation_move_one": "{count} Datei verschieben", + "storage_operation_move_other": "{count} Dateien verschieben", + "storage_operation_paste_one": "{count} Datei einfügen", + "storage_operation_paste_other": "{count} Dateien einfügen", + "storage_operation_rename": "Umbenennen", + "storage_operation_done": "Fertig", + "storage_operation_failed": "Fehlgeschlagen", + "storage_operation_cancelled": "Abgebrochen", + "storage_operation_interrupted": "Unterbrochen", + "storage_operations_label": "Vorgänge", + "storage_operations_cancel": "Vorgang abbrechen", + "storage_operations_progress": "{completed} von {total} fertig", + "storage_operations_error_generic": "Ein Fehler ist aufgetreten", + "storage_operations_active": "Aktiv", + "storage_operations_history": "Verlauf", + "storage_operations_clear_history": "Verlauf löschen", + "storage_operations_interrupted_tooltip": "Dieser Vorgang wurde durch ein Neuladen der Seite unterbrochen", + "storage_operations_speed": "Geschwindigkeit", + "storage_operations_remaining": "verbleibend", + "storage_action_rename_inline_label": "Neuer Name", + "storage_action_rename_inline_cancel": "Abbrechen", + "storage_rename_success": "In \"{name}\" umbenannt.", + "storage_rename_error": "\"{name}\" konnte nicht umbenannt werden. Bitte versuchen Sie es erneut.", + "storage_rename_error_not_connected": "Keine Speicherverbindung konfiguriert. Bitte verbinden Sie sich zuerst.", + "storage_rename_error_access_denied": "Zugriff verweigert. Sie haben keine Berechtigung zum Umbenennen.", + "storage_rename_error_not_found": "Das Element wurde nicht gefunden. Es wurde möglicherweise verschoben oder gelöscht.", + "storage_rename_error_conflict": "Eine Datei oder ein Ordner namens \"{name}\" ist an diesem Ort bereits vorhanden.", "timestamp_just_now": "gerade eben", "timestamp_minutes_ago": [ { diff --git a/messages/en.json b/messages/en.json index a6ded56d..cdf1ae5a 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1,5 +1,7 @@ { "$schema": "https://inlang.com/schema/inlang-message-format", + "action_close": "Close", + "action_dismiss": "Dismiss", "dashboard_welcome": "Welcome back", "dashboard_subtitle": "Stackable Unified Data Platform overview", "dashboard_services": "Services", @@ -21,6 +23,7 @@ "nav_badge_soon": "Soon", "sidebar_label": "Sidebar", "sidebar_nav_label": "Main navigation", + "navigation_loading": "Loading…", "sidebar_close_nav": "Close navigation", "sidebar_expand": "Expand sidebar", "sidebar_collapse": "Collapse sidebar", @@ -94,7 +97,7 @@ "trino_catalog_error": "Failed to load catalog", "trino_catalog_load_children_error": "Failed to load", "trino_view_in_trino": "View in Trino", - "trino_tab_new": "New tab", + "trino_tab_new": "New Tab", "trino_tab_close": "Close tab {name}", "trino_tab_default_name": "Untitled", "trino_tab_rename": "Rename tab", @@ -145,13 +148,33 @@ "storage_connect_secret_key": "Secret key", "storage_connect_submit": "Connect", "storage_connect_reconnecting": "Reconnecting to storage…", + "storage_connect_timeout": "Connection timed out. The storage backend did not respond.", + "storage_connect_cancel": "Cancel", "storage_connect_error": "Could not connect — check the endpoint and credentials.", + "storage_connect_error_unreachable": "Could not connect to the selected storage — the endpoint may be unreachable.", + "storage_connect_error_access_denied": "Access denied — check your credentials.", + "storage_connect_error_not_found": "Could not find the storage backend — check the endpoint.", + "storage_connect_error_server_error": "The storage backend returned an error — check the endpoint and credentials.", + "storage_connect_error_network": "Could not reach the storage backend — check the host and port.", + "storage_connect_error_hdfs": "HDFS connections are not yet supported", "storage_connect_saved": "Saved connections", "storage_connect_no_saved": "No saved connections yet", "storage_connect_forget": "Delete", "storage_connect_forget_confirm": "Delete {endpoint} from saved connections?", "storage_connect_forget_cancel": "Cancel", "storage_connect_forget_label": "Delete connection to {endpoint}", + "storage_connect_name": "Connection name", + "storage_connect_name_placeholder": "e.g. Primary S3", + "storage_connect_additional_buckets": "Additional buckets", + "storage_connect_additional_buckets_hint": "Bucket names not returned by ListBuckets, one per line", + "storage_connect_duplicate_warning": "Duplicate credentials detected", + "storage_connect_delete_label": "Delete connection {name}", + "storage_connect_delete_confirm_title": "Delete \"{name}\"?", + "storage_connect_delete_confirm_message": "The saved credentials will be permanently removed.", + "storage_connect_delete_confirm_button": "Delete", + "storage_connect_delete_cancel": "Cancel", + "storage_connect_add_new": "Add new connection", + "storage_connect_testing": "Testing connection…", "storage_connect_copy": "Copy", "storage_connect_copied": "Copied", "storage_connect_copy_all": "Copy all", @@ -193,6 +216,16 @@ "storage_buckets_subtitle": "Browse and manage your stored objects.", "storage_view_all_buckets": "View all buckets", "storage_buckets_empty": "No buckets found", + "storage_add_bucket": "Add bucket", + "storage_add_bucket_title": "Connect to a bucket", + "storage_add_bucket_subtitle": "Enter the name of a bucket you have access to.", + "storage_add_bucket_name_label": "Bucket name", + "storage_add_bucket_name_placeholder": "my-bucket", + "storage_add_bucket_submit": "Connect", + "storage_add_bucket_cancel": "Cancel", + "storage_add_bucket_error_access_denied": "Access denied — you do not have permission to read this bucket.", + "storage_add_bucket_error_not_found": "Bucket not found — check the name and try again.", + "storage_add_bucket_error_unknown": "Could not connect to this bucket — check the name and try again.", "storage_bucket_empty": "This bucket is empty", "storage_folder": "folder", "storage_folders": "folders", @@ -223,6 +256,7 @@ "storage_paste_plural": "Paste {count} items", "storage_selected": "{count} selected", "storage_action_preview": "Preview", + "storage_action_actions_for": "Actions for {name}", "storage_action_refresh": "Refresh", "storage_action_preview_no_selection": "No file selected for preview.", "storage_action_download_no_selection": "No file selected for download.", @@ -234,10 +268,14 @@ "storage_action_delete": "Delete", "storage_action_paste": "Paste", "storage_action_pin": "Pin this location", + "storage_action_details": "Details", "storage_action_unpin": "Unpin", "storage_action_copy_filename": "Copy filename", "storage_action_copy_filename_success": "Filename copied to clipboard.", "storage_action_copy_filename_error": "Could not copy filename to clipboard.", + "storage_action_copy_directory_name": "Copy directory name", + "storage_action_copy_directory_name_success": "Directory name copied to clipboard.", + "storage_action_copy_directory_name_error": "Could not copy directory name to clipboard.", "storage_action_copy_path": "Copy path", "storage_action_copy_path_success": "Path copied to clipboard.", "storage_action_copy_path_error": "Could not copy path to clipboard.", @@ -260,10 +298,11 @@ "storage_parent_dir": "Parent directory", "storage_loading": "Loading…", "storage_breadcrumb_more": "More folders", + "storage_error_breadcrumb": "breadcrumb", "storage_error_title": "Storage error", - "storage_error_access_denied": "You do not have permission to access the bucket \u201c{bucket}\u201d.", - "storage_error_not_found": "The bucket \u201c{bucket}\u201d does not exist.", - "storage_error_storage_error": "An error occurred while accessing the bucket \u201c{bucket}\u201d.", + "storage_error_access_denied": "You do not have permission to access the bucket “{bucket}”.", + "storage_error_not_found": "The bucket “{bucket}” does not exist.", + "storage_error_storage_error": "An error occurred while accessing the bucket “{bucket}”.", "storage_error_back_to_storage": "Back to storage", "storage_error_go_back": "Go back", "storage_download_error_title": "Download failed", @@ -320,12 +359,25 @@ "storage_preview_image_alt": "Preview of {name}", "storage_preview_csv_columns": "{count} more columns", "storage_preview_csv_rows": "Showing first {count} rows", + "storage_preview_csv_rows_complete": "Showing all {count} rows", "storage_preview_parquet_rows": "Showing first {count} of {total} rows (parquet)", + "storage_preview_infinite_scroll_disabled": "This is the end of the preview. Download the full file or ask the administrator to enable infinite scrolling to load more rows in this preview.", "storage_preview_pdf_too_large": "PDF is too large to preview inline.", "storage_preview_image_too_large": "Image is too large to display.", "storage_preview_image_too_large_desc": "The file exceeds the maximum preview size. Download the full file to view it.", "storage_preview_maximise": "Maximise", "storage_preview_restore": "Restore", + "storage_editor_save": "Save", + "storage_editor_saving": "Saving…", + "storage_editor_saved": "Saved", + "storage_editor_unsaved_title": "Unsaved changes", + "storage_editor_unsaved_desc": "You have unsaved changes. What would you like to do?", + "storage_editor_save_and_close": "Save and close", + "storage_editor_discard": "Discard", + "storage_editor_cancel": "Cancel", + "storage_editor_error": "Failed to save file.", + "storage_editor_too_large": "File too large to save. The maximum editable file size is {limit}.", + "storage_editor_too_large_badge": "Read-only: exceeds {limit}", "storage_context_menu_actions": "Actions", "storage_action_upload": "Upload", "storage_upload_title": "Upload", @@ -336,7 +388,7 @@ "storage_upload_to_prefix": "Uploading to: {prefix}", "storage_upload_total_size": "Total: {size}", "storage_upload_start": "Upload", - "storage_upload_checking": "Checking for conflicts\u2026", + "storage_upload_checking": "Checking for conflicts…", "storage_upload_conflicts_title": "Files already exist", "storage_upload_conflicts_desc": "Choose what to do for each conflicting file.", "storage_upload_skip_all": "Skip all", @@ -348,13 +400,13 @@ "storage_upload_rename_same_name_error": "Please enter a different name, or select Replace or Skip.", "storage_upload_rename_confirm_action": "Confirm name", "storage_upload_rename_taken": "This name already exists here. Please choose a different name.", - "storage_upload_uploading": "Uploading\u2026 {pct}%", + "storage_upload_uploading": "Uploading… {pct}%", "storage_upload_status_queued": "queued", "storage_upload_status_done": "done", "storage_upload_status_skipped": "skipped", "storage_upload_status_failed": "failed", "storage_upload_complete_title": "Upload complete", - "storage_upload_complete_summary": "{uploaded} uploaded \u00b7 {skipped} skipped \u00b7 {failed} failed", + "storage_upload_complete_summary": "{uploaded} uploaded · {skipped} skipped · {failed} failed", "storage_upload_done": "Done", "storage_upload_success": "File uploaded successfully.", "storage_upload_error_not_connected": "No storage connection configured. Please connect first.", @@ -364,13 +416,260 @@ "storage_upload_error_server_error": "A server error occurred. Please retry.", "storage_upload_error_unknown": "An unexpected error occurred. Please retry.", "storage_upload_overwrite_title": "File already exists", - "storage_upload_overwrite_message": "An object named \u201c{name}\u201d already exists in this location. What would you like to do?", + "storage_upload_overwrite_message": "An object named “{name}” already exists in this location. What would you like to do?", "storage_upload_overwrite_replace": "Replace", "storage_upload_overwrite_cancel": "Cancel", "storage_upload_overwrite_rename": "Rename", "storage_upload_rename_confirm": "Upload with this name", "storage_upload_retry": "Retry", "storage_upload_close": "Close", + "storage_action_create": "Create", + "storage_create_file": "New text file", + "storage_create_folder": "New directory", + "storage_create_name": "Name", + "storage_create_placeholder": "Enter name…", + "storage_create_confirm": "Create", + "storage_create_cancel": "Cancel", + "storage_create_error": "Failed to create {name}", + "storage_tab_new": "New Tab", + "storage_tab_close": "Close tab", + "storage_tab_rename": "Rename tab", + "storage_tab_list": "Explorer tabs", + "storage_tab_context_menu": "Tab options", + "storage_restore_tabs_message": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "You have 1 saved tab from your last session.", + "countPlural=other": "You have {count} saved tabs from your last session." + } + } + ], + "storage_restore_tabs_action": "Restore tabs", + "storage_preview_parquet_tab_aria": "Parquet preview tabs", + "storage_preview_parquet_tab_metadata": "Metadata", + "storage_preview_parquet_tab_data": "Data", + "storage_preview_parquet_blocked_title": "Preview blocked", + "storage_preview_parquet_blocked_desc": "This parquet file uses a compression type that has been disallowed by the administrator. Contact your administrator if you believe this to be an issue.", + "storage_preview_parquet_overview": "Overview", + "storage_preview_parquet_file_size": "File size", + "storage_preview_parquet_total_rows": "Total rows", + "storage_preview_parquet_total_columns": "Total columns", + "storage_preview_parquet_version": "Version", + "storage_preview_parquet_created_by": "Created by", + "storage_preview_parquet_schema": "Schema", + "storage_preview_parquet_column": "Column", + "storage_preview_parquet_type": "Type", + "storage_preview_parquet_compression_indexes": "Compression & Indexes", + "storage_preview_parquet_row_groups": "Row groups", + "storage_preview_parquet_row_group": "Group", + "storage_preview_parquet_offset_index": "Offset index", + "storage_preview_parquet_column_index": "Column index", + "storage_preview_parquet_available": "Available", + "storage_preview_parquet_missing": "Missing", + "storage_preview_parquet_none": "None", + "storage_preview_parquet_compression": "Compression", + "storage_preview_parquet_uncompressed": "Uncompressed", + "storage_preview_parquet_compressed": "Compressed", + "storage_preview_parquet_size": "Size", + "storage_preview_parquet_statistics": "Statistics", + "storage_preview_parquet_min": "Min", + "storage_preview_parquet_max": "Max", + "storage_preview_parquet_null_count": "Null count", + "storage_preview_parquet_distinct_count": "Distinct count", + "storage_preview_parquet_not_stored": "Not stored", + "storage_preview_parquet_arrow_schema": "Arrow schema", + "storage_preview_parquet_arrow_schema_present": "Embedded Arrow schema ({size})", + "storage_preview_parquet_uniform": "uniform", + "storage_archive_open_error": "Could not open archive. The format may be unsupported or the archive is corrupt.", + "storage_archive_too_large": "Archive is too large to preview.", + "storage_archive_exit": "Exit archive", + "storage_details_title": "Details", + "storage_details_file_title": "File Details", + "storage_details_folder_title": "Directory Details", + "storage_details_bucket_title": "Bucket Details", + "storage_details_close": "Close", + "storage_details_maximise": "Maximise", + "storage_details_restore": "Restore", + "storage_details_property": "Property", + "storage_details_value": "Value", + "storage_details_name": "Name", + "storage_details_size": "Size", + "storage_details_last_modified": "Last modified", + "storage_details_content_type": "Content type", + "storage_details_etag": "ETag", + "storage_details_version_id": "Version ID", + "storage_details_storage_class": "Storage class", + "storage_details_is_delete_marker": "Delete marker", + "storage_details_yes": "Yes", + "storage_details_no": "No", + "storage_details_calculate_size": "Calculate directory size", + "storage_details_calculating": "Calculating…", + "storage_details_calculating_desc": "Listing all objects in this directory…", + "storage_details_keys_found": "{count} objects found", + "storage_details_file_count": "{count} files", + "storage_details_folder_count": "{count} folders", + "storage_details_total_size": "Total size", + "storage_details_tree_visualization": "Size composition", + "storage_details_versioning": "Versioning", + "storage_details_versioning_enabled": "Enabled", + "storage_details_versioning_suspended": "Suspended", + "storage_details_versioning_disabled": "Disabled", + "storage_details_lifecycle_rules": "Lifecycle Rules", + "storage_details_lifecycle_rule_id": "Rule ID", + "storage_details_lifecycle_status": "Status", + "storage_details_lifecycle_filter": "Filter", + "storage_details_lifecycle_expiration": "Expiration", + "storage_details_lifecycle_noncurrent_expiration": "Noncurrent version expiration", + "storage_details_lifecycle_transition": "Transition", + "storage_details_lifecycle_days": "{days} days", + "storage_details_lifecycle_abort_mpu": "Abort incomplete uploads", + "storage_details_lifecycle_days_after_initiation": "{days}d after initiation", + "storage_details_lifecycle_noncurrent_transition": "Noncurrent transition", + "storage_details_lifecycle_transition_to": "→ {storageClass}", + "storage_details_lifecycle_prefix_filter": "Prefix: {prefix}", + "storage_details_lifecycle_all_objects": "All objects", + "storage_details_lifecycle_no_rules": "No lifecycle rules configured", + "storage_details_tags": "Tags", + "storage_details_no_tags": "No tags", + "storage_details_custom_metadata": "Custom Metadata", + "storage_details_error_not_connected": "No storage connection configured", + "storage_details_error_fetch_file": "Failed to fetch file details ({status})", + "storage_details_error_fetch_bucket": "Failed to fetch bucket details ({status})", + "storage_details_error_fetch_dir_meta": "Failed to fetch directory metadata ({status})", + "storage_details_error_calc_size": "Failed to calculate directory size ({status})", + "storage_details_error_unknown": "Unknown error", + "storage_details_error_no_body": "No response body", + "storage_details_unnamed_rule": "(unnamed)", + "storage_details_treemap_aria": "Treemap visualization of directory size composition", + "storage_details_treemap_more": "{count} more", + "storage_details_copy_dir_name": "Copy directory name", + "storage_details_copy_file_name": "Copy file name", + "storage_details_copy_full_path": "Copy full path", + "storage_details_tab_overview": "Overview", + "storage_details_tab_composition": "Size composition", + "storage_details_tab_contents": "Contents", + "storage_details_tab_lifecycle": "Lifecycle", + "storage_details_file_path": "Path", + "storage_details_bucket_name": "Bucket", + "storage_details_owner": "Owner", + "storage_details_permissions": "Permissions", + "storage_details_depth": "Depth", + "storage_details_marker_exists": "Folder marker", + "storage_details_marker_none": "No folder marker object", + "storage_details_encryption": "Encryption", + "storage_details_object_lock": "Object lock", + "storage_details_object_lock_mode": "Lock mode", + "storage_details_object_lock_until": "Retain until", + "storage_action_cut_success": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 item cut", + "countPlural=other": "{count} items cut" + } + } + ], + "storage_action_copy_success": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 item copied", + "countPlural=other": "{count} items copied" + } + } + ], + "storage_action_paste_success": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 item pasted", + "countPlural=other": "{count} items pasted" + } + } + ], + "storage_action_paste_error": "Could not paste items. Please try again.", + "storage_action_paste_partial": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 item could not be pasted.", + "countPlural=other": "{count} items could not be pasted." + } + } + ], + "storage_action_paste_error_source_not_found": "Could not paste — the source items may have been deleted or moved.", + "storage_action_paste_archive_error": "Cannot paste inside an archive.", + "storage_action_move_success": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 item moved", + "countPlural=other": "{count} items moved" + } + } + ], + "storage_action_move_partial": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "1 item could not be moved.", + "countPlural=other": "{count} items could not be moved." + } + } + ], + "storage_action_move_error": "Could not move items. Please try again.", + "storage_action_move_error_not_connected": "No storage connection configured. Please connect first.", + "storage_action_move_error_access_denied": "Access denied. You do not have permission to move items.", + "storage_move_confirm_title": "Move items", + "storage_move_confirm_body": [ + { + "declarations": ["input count", "local countPlural = count: plural"], + "selectors": ["countPlural"], + "match": { + "countPlural=one": "Move 1 item to \"{destination}\"?", + "countPlural=other": "Move {count} items to \"{destination}\"?" + } + } + ], + "storage_move_confirm_label": "Move", + "storage_move_confirm_cancel": "Cancel", + "storage_move_confirm_more": "+{count} more", + "storage_move_confirm_total_size": "Total: {size}", + "storage_operation_move_one": "Move {count} file", + "storage_operation_move_other": "Move {count} files", + "storage_operation_paste_one": "Paste {count} file", + "storage_operation_paste_other": "Paste {count} files", + "storage_operation_rename": "Rename", + "storage_operation_done": "Done", + "storage_operation_failed": "Failed", + "storage_operation_cancelled": "Cancelled", + "storage_operation_interrupted": "Interrupted", + "storage_operations_label": "Operations", + "storage_operations_cancel": "Cancel operation", + "storage_operations_progress": "{completed} of {total} done", + "storage_operations_error_generic": "An error occurred", + "storage_operations_active": "Active", + "storage_operations_history": "History", + "storage_operations_clear_history": "Clear history", + "storage_operations_interrupted_tooltip": "This operation was interrupted by a page reload", + "storage_operations_speed": "Speed", + "storage_operations_remaining": "remaining", + "storage_action_rename_inline_label": "New name", + "storage_action_rename_inline_cancel": "Cancel", + "storage_rename_success": "Renamed to \"{name}\".", + "storage_rename_error": "Could not rename \"{name}\". Please try again.", + "storage_rename_error_not_connected": "No storage connection configured. Please connect first.", + "storage_rename_error_access_denied": "Access denied. You do not have permission to rename.", + "storage_rename_error_not_found": "The item could not be found. It may have been moved or deleted.", + "storage_rename_error_conflict": "A file or folder named \"{name}\" already exists in this location.", "timestamp_just_now": "just now", "timestamp_minutes_ago": [ { diff --git a/package-lock.json b/package-lock.json index 24b34871..bf545d49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,21 +7,27 @@ "": { "name": "@stackable/stackable-cockpit", "version": "0.0.1", - "license": "Apache-2.0", + "license": "OSL-3.0", "dependencies": { "@aws-sdk/client-s3": "^3.1041.0", "@aws-sdk/lib-storage": "^3.1045.0", + "@better-auth/drizzle-adapter": "^1.6.20", "@internationalized/date": "^3.11.0", "@smithy/node-http-handler": "4.9.1", + "adm-zip": "^0.5.17", "antlr4-c3": "^3.4.4", "antlr4ng": "^3.0.16", - "better-auth": "^1.5.4", + "better-auth": "^1.6.20", + "drizzle-orm": "^0.45.2", "hyparquet": "^1.25.8", "hyparquet-compressors": "^1.1.1", "monaco-editor": "^0.55.1", + "papaparse": "^5.5.3", + "pg": "^8.21.0", "pino": "^10.3.1", "pretty-bytes": "^7.1.0", "prom-client": "^15.1.3", + "tar-stream": "^3.2.0", "undici": "^7.24.4" }, "devDependencies": { @@ -29,18 +35,28 @@ "@eslint/compat": "^2.0.2", "@eslint/js": "^9.39.2", "@faker-js/faker": "^10.4.0", + "@iconify-json/lsicon": "^1.2.5", + "@iconify-json/material-icon-theme": "^1.2.67", "@iconify-json/material-symbols": "^1.2.74", + "@iconify-json/vscode-icons": "^1.2.55", "@inlang/paraglide-js": "^2.12.0", "@playwright/test": "^1.58.2", "@sveltejs/adapter-node": "^5.5.3", "@sveltejs/kit": "^2.53.0", "@sveltejs/vite-plugin-svelte": "^6.2.4", "@tailwindcss/vite": "^4.2.1", + "@testcontainers/postgresql": "^12.0.1", + "@types/adm-zip": "^0.5.8", "@types/node": "^24", + "@types/papaparse": "^5.5.2", + "@types/pg": "^8.20.0", + "@types/tar-stream": "^3.1.4", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", "antlr-ng": "^1.0.10", + "archunit": "^2.3.3", "daisyui": "^5.5.19", + "drizzle-kit": "^0.31.10", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", "eslint-plugin-better-tailwindcss": "^4.3.0", @@ -56,6 +72,7 @@ "svelte-check": "^4.4.3", "sveltekit-superforms": "^2.30.0", "tailwindcss": "^4.2.1", + "testcontainers": "^12.0.1", "tsx": "^4.23.13", "typescript": "^5.9.3", "typescript-eslint": "^8.56.1", @@ -68,8 +85,6 @@ }, "node_modules/@antfu/install-pkg": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", - "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", "dev": true, "license": "MIT", "dependencies": { @@ -82,8 +97,6 @@ }, "node_modules/@ark/schema": { "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@ark/schema/-/schema-0.56.0.tgz", - "integrity": "sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==", "dev": true, "license": "MIT", "optional": true, @@ -93,16 +106,12 @@ }, "node_modules/@ark/util": { "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@ark/util/-/util-0.56.0.tgz", - "integrity": "sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==", "dev": true, "license": "MIT", "optional": true }, "node_modules/@aws-crypto/crc32": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", - "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", @@ -115,8 +124,6 @@ }, "node_modules/@aws-crypto/crc32c": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", - "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", @@ -126,8 +133,6 @@ }, "node_modules/@aws-crypto/sha1-browser": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", - "integrity": "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", @@ -140,8 +145,6 @@ }, "node_modules/@aws-crypto/sha256-browser": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", @@ -155,8 +158,6 @@ }, "node_modules/@aws-crypto/sha256-js": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", @@ -169,8 +170,6 @@ }, "node_modules/@aws-crypto/supports-web-crypto": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -178,8 +177,6 @@ }, "node_modules/@aws-crypto/util": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.222.0", @@ -189,8 +186,6 @@ }, "node_modules/@aws-sdk/client-s3": { "version": "3.1053.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1053.0.tgz", - "integrity": "sha512-/oGxoB6p1Nqs935Blt+v1o+anSCEf2n3RjIrcLz84i4cn2Gr+Z7JpDdUkG5+74r5ctqEPG7k/phTGbJ9fNKnHg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", @@ -218,8 +213,6 @@ }, "node_modules/@aws-sdk/core": { "version": "3.974.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.13.tgz", - "integrity": "sha512-+Y5/4tHki0uYgyx8eun146DegRVQBpdKGK5RbV0FTKJPpaKTchvqVxrrRFK6Wk0JksO4iAZKw3eqxGEIwtO98w==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.9", @@ -237,8 +230,6 @@ }, "node_modules/@aws-sdk/crc64-nvme": { "version": "3.972.9", - "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.9.tgz", - "integrity": "sha512-P+QGozmXn2mZZI7sDgk+aUm+RTI61MPSFB+Ir2vjEjEbEsE4e7hYtzrDvAUxZy9ko81h53e11+F/GYlvwDkaOQ==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.2", @@ -250,8 +241,6 @@ }, "node_modules/@aws-sdk/credential-provider-env": { "version": "3.972.39", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.39.tgz", - "integrity": "sha512-29wX9zpAvEt1vcj0psha+y6ygBHy2V/S72mp6e7q0KARLWXq+pwE/lR6qGkwknQvruh52lXvlqZIga8Hdxkucw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -266,8 +255,6 @@ }, "node_modules/@aws-sdk/credential-provider-http": { "version": "3.972.41", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.41.tgz", - "integrity": "sha512-IA3CQTjtJkb6u1H4mE4936c8OPBMa9Jggtwe8U2Mqw/vvb/tZ5Ebd0mcZcX0uKWQhOyYo/+qNIwkV5Xh+FeJJA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -284,8 +271,6 @@ }, "node_modules/@aws-sdk/credential-provider-ini": { "version": "3.972.43", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.43.tgz", - "integrity": "sha512-4mzII+3mZEVXXE1xzrLQrCJL7/r62A63bA6SVzZoNL5rqCJghpf+xgGltVrIBBs0n+mOZBKrQl2tRREtvZ5l6A==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -308,8 +293,6 @@ }, "node_modules/@aws-sdk/credential-provider-login": { "version": "3.972.43", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.43.tgz", - "integrity": "sha512-HG7kQCwXtbv3oBV61Ins0oNX8KKyvrMqqRkb6ZiAfQHbMuHaiNaEb2KnpKLPkNpqImSBK82UkVE/kaY6IfWikA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -325,8 +308,6 @@ }, "node_modules/@aws-sdk/credential-provider-node": { "version": "3.972.44", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.44.tgz", - "integrity": "sha512-sDaBIT0yrNNIPfvlsiTCmANm07zKju+ipWODjEXgZlsjMeIJR3LVp7RDyAOzUoAsTbDfYKDWp+i5WrFiQP6rmQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.39", @@ -347,8 +328,6 @@ }, "node_modules/@aws-sdk/credential-provider-process": { "version": "3.972.39", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.39.tgz", - "integrity": "sha512-2k/amBifLd75eXNwgvPw/2lKYSQ3NhvHQgkVKVjfUq13/eJ3JRtHmznuFenn74OK3sSfp4SMy1YB2w+UVXoKqA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -363,8 +342,6 @@ }, "node_modules/@aws-sdk/credential-provider-sso": { "version": "3.972.43", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.43.tgz", - "integrity": "sha512-LPc3+Y4vhH1T4x6CMqwCM6hk5+SRf/Lwmgm8INm95wxTtIRHcMwQUVkDzWu4Iw/RSncxYM2BC01OrYbxOPZvyg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -381,8 +358,6 @@ }, "node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.972.43", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.43.tgz", - "integrity": "sha512-wQtL34lUD/09VXjwAUo2T+I3aEXRDxMB3DKmTJL/Zj0Gi6sLDTrVhae1XVt01yzkquOWajI/sZW72JGDZ1ciTw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -398,8 +373,6 @@ }, "node_modules/@aws-sdk/lib-storage": { "version": "3.1053.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1053.0.tgz", - "integrity": "sha512-Y5fyrJ2Qln3lmU0I335no+zdyytpM7svvYOYadZiV2bXGDXEO26A8B+4iGW264GvBO4jnl/iPHVZ/hJIqXekAA==", "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.24.3", @@ -416,20 +389,8 @@ "@aws-sdk/client-s3": "^3.1053.0" } }, - "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { "version": "3.972.15", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.15.tgz", - "integrity": "sha512-O2HDANa+MrvbxpaRVQDiH3T13uAa9AkMjKyZmDygwauAmmvqZ5B0iRmKW+fuVGW6NPXuyXurFgIx69lSvmAWGA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -444,8 +405,6 @@ }, "node_modules/@aws-sdk/middleware-expect-continue": { "version": "3.972.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.13.tgz", - "integrity": "sha512-sHiqIFg8o2ipT7t40B89Vj0ubSUtY6OSt/+Ee/OXhHch5K4+81zP2+QX8Lkc/nJ2QSmCySxOke7TEbmX69fe2g==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.9", @@ -459,8 +418,6 @@ }, "node_modules/@aws-sdk/middleware-flexible-checksums": { "version": "3.974.21", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.21.tgz", - "integrity": "sha512-alAu9heyiBK/OmRNXVxq8mmPTgeW2AQ6EYjRsI38kPZa1MZvt2Jh+BlGq7/GG9OVXOaEgD7DlGj/Lzfy5OmuEg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", @@ -479,8 +436,6 @@ }, "node_modules/@aws-sdk/middleware-location-constraint": { "version": "3.972.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.11.tgz", - "integrity": "sha512-hkfspNUP4criAH6ton6BGKgnm5dZx+7bUOy1YqlTfejDeUPAM23D81q/IX+hdlS3KUsfwGz5ADTqZWKBEUpf4A==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.9", @@ -493,8 +448,6 @@ }, "node_modules/@aws-sdk/middleware-sdk-s3": { "version": "3.972.42", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.42.tgz", - "integrity": "sha512-/xNqNGXv9LaxZd25L9VV4pnSOw9OdDNO4rAHamM+h3KQBSITljIH9vk3dveGga1I2j36lQd0rdG3gjNEXvtNew==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -511,8 +464,6 @@ }, "node_modules/@aws-sdk/middleware-ssec": { "version": "3.972.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.11.tgz", - "integrity": "sha512-7PQvGNhtveKlvVqNahqWx5yrwxP7ecwAoB1dYBf8eKwfo2tzzCbNnW+q2nO3N066ktQaB4iBQbDRWtizm+amoQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.9", @@ -525,8 +476,6 @@ }, "node_modules/@aws-sdk/nested-clients": { "version": "3.997.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.11.tgz", - "integrity": "sha512-nWXXJ1r/r8N2Gw1pWolRgED38/A9A8DHR2ETWIv220zh4PZHcybbR4hUVWWktmNXTRHzDJwRluapHn0rZxuoqA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -546,8 +495,6 @@ }, "node_modules/@aws-sdk/signature-v4-multi-region": { "version": "3.996.28", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.28.tgz", - "integrity": "sha512-qs9z5LqXO/CZC2Lg9SGKpoLU8Rhi+m2pFKZqfO9pytX1clc0katqtsDNupJxFy0xT9wsZSPzM2v1y+/H/zfp5Q==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.9", @@ -562,8 +509,6 @@ }, "node_modules/@aws-sdk/token-providers": { "version": "3.1052.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1052.0.tgz", - "integrity": "sha512-QqZNB3so7UIDxZtroc85TQaLVxdZRFm0eWM1CSR2N+b06as9TOrilvrlTZuj3guYlxMs6yLOgGxnklJ5qMYtTw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.13", @@ -579,8 +524,6 @@ }, "node_modules/@aws-sdk/types": { "version": "3.973.9", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.9.tgz", - "integrity": "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.2", @@ -592,8 +535,6 @@ }, "node_modules/@aws-sdk/util-locate-window": { "version": "3.965.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", - "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -604,8 +545,6 @@ }, "node_modules/@aws-sdk/xml-builder": { "version": "3.972.25", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.25.tgz", - "integrity": "sha512-GH+Kjz4nPKWKHnsiQpnhP1MJdTGIcK4rAka6tzakgjjUkVgNsmPeEbbRAf09SzS1hjGu6duGHCBsxYke0BhHjQ==", "license": "Apache-2.0", "dependencies": { "@nodable/entities": "2.1.0", @@ -619,8 +558,6 @@ }, "node_modules/@aws/lambda-invoke-store": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", - "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -628,9 +565,7 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -638,9 +573,7 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -648,9 +581,7 @@ }, "node_modules/@babel/parser": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.7" @@ -664,8 +595,6 @@ }, "node_modules/@babel/runtime": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "dev": true, "license": "MIT", "optional": true, @@ -675,9 +604,7 @@ }, "node_modules/@babel/types": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.29.7", @@ -687,68 +614,154 @@ "node": ">=6.9.0" } }, + "node_modules/@balena/dockerignore": { + "version": "1.0.2", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@bcoe/v8-coverage": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, "license": "MIT", "engines": { "node": ">=18" } }, - "node_modules/@better-auth/utils": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.1.tgz", - "integrity": "sha512-+CGp4UmZSUrHHnpHhLPYu6cV+wSUSvVbZbNykxhUDocpVNTo9uFFxw/NqJlh1iC4wQ9HKKWGCKuZ5wUgS0v6Kg==", - "license": "MIT" + "node_modules/@better-auth/core": { + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.20.tgz", + "integrity": "sha512-y73I1xNXuNYiHBFduWGRcJ2ro2rNuVDEYkgVMJtIaRXtbosdXHs9gfyQrHecgeHMHKx1SYSBT/CExak0vVMTng==", + "license": "MIT", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.39.0", + "@standard-schema/spec": "^1.1.0", + "zod": "^4.3.6" + }, + "peerDependencies": { + "@better-auth/utils": "0.4.2", + "@better-fetch/fetch": "1.3.1", + "@cloudflare/workers-types": ">=4", + "@opentelemetry/api": "^1.9.0", + "better-call": "1.3.6", + "jose": "^6.1.0", + "kysely": "^0.28.5 || ^0.29.0", + "nanostores": "^1.0.1" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + } + } }, - "node_modules/@better-fetch/fetch": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.21.tgz", - "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==" + "node_modules/@better-auth/drizzle-adapter": { + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.6.20.tgz", + "integrity": "sha512-hJHfCdAiZrC7EmZAt3NAiGgcNo9Y5Qz3PLL+a9rODXaAJGCMvzUJniqef9wHuJBwU0SWW+2f4wXe8xQmaC/IKQ==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.20", + "@better-auth/utils": "0.4.2", + "drizzle-orm": "^0.45.2" + }, + "peerDependenciesMeta": { + "drizzle-orm": { + "optional": true + } + } }, - "node_modules/@chevrotain/cst-dts-gen": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.5.0.tgz", - "integrity": "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@chevrotain/gast": "10.5.0", - "@chevrotain/types": "10.5.0", - "lodash": "4.17.21" + "node_modules/@better-auth/kysely-adapter": { + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@better-auth/kysely-adapter/-/kysely-adapter-1.6.20.tgz", + "integrity": "sha512-Uvpmgbx5y8JqXroVanNzDdKzOl3HojoTz+/X6MR6zOUr25IzlYz660mjnu0rxKiIF55kD3CroqFsDzjNUw7ERw==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.20", + "@better-auth/utils": "0.4.2", + "kysely": "^0.28.17 || ^0.29.0" + }, + "peerDependenciesMeta": { + "kysely": { + "optional": true + } } }, - "node_modules/@chevrotain/gast": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.5.0.tgz", - "integrity": "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@chevrotain/types": "10.5.0", - "lodash": "4.17.21" + "node_modules/@better-auth/memory-adapter": { + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@better-auth/memory-adapter/-/memory-adapter-1.6.20.tgz", + "integrity": "sha512-J5Ni0LlFijbzXlwu2rFHaD8zEFocmajyzWkRnHsq8LhV/Dk4iWQwwnqzLrPoDQEj8roECAUF03hrIeMzqWRqJQ==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.20", + "@better-auth/utils": "0.4.2" } }, - "node_modules/@chevrotain/types": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.5.0.tgz", - "integrity": "sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==", - "license": "Apache-2.0", - "peer": true + "node_modules/@better-auth/mongo-adapter": { + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@better-auth/mongo-adapter/-/mongo-adapter-1.6.20.tgz", + "integrity": "sha512-ClDBJf6h4g85WJswxwQwxLaiyRU67Gmz/uaIf19tY1gqlLJDykSGjmqRNSBMG5rWABNzcNqbO4KG31rYUldbIw==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.20", + "@better-auth/utils": "0.4.2", + "mongodb": "^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "mongodb": { + "optional": true + } + } }, - "node_modules/@chevrotain/utils": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.5.0.tgz", - "integrity": "sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==", - "license": "Apache-2.0", - "peer": true + "node_modules/@better-auth/prisma-adapter": { + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@better-auth/prisma-adapter/-/prisma-adapter-1.6.20.tgz", + "integrity": "sha512-WhYdhSGuVSfu1peCSf2snmmVzfWjRaEvbSrsNCusiwGE9l94HlES4mjSPM48fed24hL7yg4j1dYK/yjEt87FpQ==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.20", + "@better-auth/utils": "0.4.2", + "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", + "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "@prisma/client": { + "optional": true + }, + "prisma": { + "optional": true + } + } + }, + "node_modules/@better-auth/telemetry": { + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.6.20.tgz", + "integrity": "sha512-3BhbY3naQDERvdJvJ7fGszVY6rpsVfc6c9uyBVZlC1coVEF/rkM0rIcjtMVI1GUH7vWy1wjR6qF5vQnMun3XNQ==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.20", + "@better-auth/utils": "0.4.2", + "@better-fetch/fetch": "1.3.1" + } + }, + "node_modules/@better-auth/utils": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.2.tgz", + "integrity": "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.0.1" + } + }, + "node_modules/@better-fetch/fetch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.3.1.tgz", + "integrity": "sha512-ABkD1WhyfPZprKRQI3bhATjeiFuNWC9PXhfGWqL+sg/gKrM977oFrYkdb4msM3hgUGonr7KlOsOFT5TU2rht9g==", + "license": "MIT" }, "node_modules/@cyclonedx/cyclonedx-npm": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@cyclonedx/cyclonedx-npm/-/cyclonedx-npm-4.2.1.tgz", - "integrity": "sha512-SOA/96sf0wsgUYCRtFkLFm6WoFhG+q1BxdC84hPSn9J3xWlH1e7OnTPJT+WNUzTqzX1nSm5JhjRX4krozu2X+g==", "dev": true, "funding": [ { @@ -781,8 +794,6 @@ }, "node_modules/@cyclonedx/cyclonedx-npm/node_modules/@cyclonedx/cyclonedx-library": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@cyclonedx/cyclonedx-library/-/cyclonedx-library-10.0.0.tgz", - "integrity": "sha512-xDXf2eqzeFHdjamj6oBV3duRSfrlmsJ5+2z9tXp7q5qxJP5Awmjf4ABSutS4qkVHHj7JzKFL/EM0V0Nihc7zPg==", "dev": true, "funding": [ { @@ -829,8 +840,6 @@ }, "node_modules/@cyclonedx/cyclonedx-npm/node_modules/ajv": { "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "optional": true, @@ -847,8 +856,6 @@ }, "node_modules/@cyclonedx/cyclonedx-npm/node_modules/commander": { "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "dev": true, "license": "MIT", "engines": { @@ -857,1792 +864,1908 @@ }, "node_modules/@cyclonedx/cyclonedx-npm/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT", "optional": true }, - "node_modules/@electric-sql/pglite": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.15.tgz", - "integrity": "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==", - "license": "Apache-2.0", - "peer": true - }, - "node_modules/@electric-sql/pglite-socket": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.0.20.tgz", - "integrity": "sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "pglite-server": "dist/scripts/server.js" - }, - "peerDependencies": { - "@electric-sql/pglite": "0.3.15" - } - }, - "node_modules/@electric-sql/pglite-tools": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.2.20.tgz", - "integrity": "sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A==", - "license": "Apache-2.0", - "peer": true, - "peerDependencies": { - "@electric-sql/pglite": "0.3.15" - } - }, - "node_modules/@emnapi/core": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", - "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", - "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } + "node_modules/@drizzle-team/brocli": { + "version": "0.10.2", + "devOptional": true, + "license": "Apache-2.0" }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", - "dev": true, + "node_modules/@esbuild-kit/core-utils": { + "version": "3.3.2", + "devOptional": true, "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "esbuild": "~0.18.20", + "source-map-support": "^0.5.21" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", - "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": { + "version": "0.18.20", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ - "arm64" + "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "netbsd" + "openbsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ - "arm64" + "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "openbsd" + "sunos" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ - "x64" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "openbsd" + "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ - "arm64" + "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "openharmony" + "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "sunos" + "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { + "version": "0.18.20", + "devOptional": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.6.5", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@esbuild-kit/core-utils": "^3.3.2", + "get-tsconfig": "^4.7.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ - "arm64" + "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "aix" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ - "ia32" + "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "android" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ - "x64" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "android" ], "engines": { "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils/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, - "license": "Apache-2.0", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@eslint/compat": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.2.tgz", - "integrity": "sha512-pR1DoD0h3HfF675QZx0xsyrsU8q70Z/plx7880NOhS02NuWLgBCOMDL787nUeQ7EWLkxv3bPQJaarjcPQb2Dwg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.1.0" - }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "peerDependencies": { - "eslint": "^8.40 || 9 || 10" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/config-helpers/node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/core": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", - "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=18" } }, - "node_modules/@eslint/css-tree": { - "version": "3.6.9", - "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-3.6.9.tgz", - "integrity": "sha512-3D5/OHibNEGk+wKwNwMbz63NMf367EoR4mVNNpxddCHKEb2Nez7z62J2U6YjtErSsZDoY0CsccmoUpdEbkogNA==", - "dev": true, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], "license": "MIT", - "dependencies": { - "mdn-data": "2.23.0", - "source-map-js": "^1.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@exodus/schemasafe": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", - "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", - "dev": true, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "optional": true + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@faker-js/faker": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.4.0.tgz", - "integrity": "sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/fakerjs" - } + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" ], "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", - "npm": ">=10" + "node": ">=18" } }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", "optional": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" + "node": ">=18" } }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=18.18.0" + "node": ">=18" } }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=18.18.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=12.22" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "2.0.2", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.0" + }, "engines": { - "node": ">=18.18" + "node": "^20.19.0 || ^22.13.0 || >=24" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependencies": { + "eslint": "^8.40 || 9 || 10" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/@iconify-json/material-symbols": { - "version": "1.2.74", - "resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.2.74.tgz", - "integrity": "sha512-GKJcvvm8A25pkh3Z2M430olvP4hDpDKg2sg7cpVnesM4bT7rExH74ThtRLWjdB86qhkxT3XrMuHRJa8LFCRmSw==", + "node_modules/@eslint/config-array": { + "version": "0.21.1", "dev": true, "license": "Apache-2.0", "dependencies": { - "@iconify/types": "*" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@iconify/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", "dev": true, - "license": "MIT" - }, - "node_modules/@iconify/utils": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.3.tgz", - "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers/node_modules/@eslint/core": { + "version": "0.17.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@iconify/types": "^2.0.0", - "import-meta-resolve": "^4.2.0" + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@inlang/paraglide-js": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@inlang/paraglide-js/-/paraglide-js-2.12.0.tgz", - "integrity": "sha512-wnqTeSLcMMS2usL8zjS8bDGs9r16X00aeoGk2wVAnPfAgCChYalKdG20pS2XtJVMM1H6nBBBLKt3ZQMnKrusKQ==", + "node_modules/@eslint/core": { + "version": "1.2.1", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@inlang/recommend-sherlock": "^0.2.1", - "@inlang/sdk": "^2.7.0", - "commander": "11.1.0", - "consola": "3.4.0", - "json5": "2.2.3", - "unplugin": "^2.1.2", - "urlpattern-polyfill": "^10.0.0" + "@types/json-schema": "^7.0.15" }, - "bin": { - "paraglide-js": "bin/run.js" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@inlang/recommend-sherlock": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@inlang/recommend-sherlock/-/recommend-sherlock-0.2.1.tgz", - "integrity": "sha512-ckv8HvHy/iTqaVAEKrr+gnl+p3XFNwe5D2+6w6wJk2ORV2XkcRkKOJ/XsTUJbPSiyi4PI+p+T3bqbmNx/rDUlg==", + "node_modules/@eslint/css-tree": { + "version": "3.6.9", "dev": true, "license": "MIT", "dependencies": { - "comment-json": "^4.2.3" + "mdn-data": "2.23.0", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/@inlang/sdk": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@inlang/sdk/-/sdk-2.7.0.tgz", - "integrity": "sha512-yJNBD0o8i29TTJqWX5uDRHxnalDGcsUDctxepzFXsUfkzqGWfiFBxODdxvReqvM2CuKAAOo/kib/F1UcgdYFNQ==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", "dev": true, "license": "MIT", "dependencies": { - "@lix-js/sdk": "0.4.7", - "@sinclair/typebox": "^0.31.17", - "kysely": "^0.27.4", - "sqlite-wasm-kysely": "0.3.0", - "uuid": "^13.0.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@internationalized/date": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.11.0.tgz", - "integrity": "sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q==", - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@eslint/js": { + "version": "9.39.2", "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", "dev": true, - "license": "ISC", - "optional": true, + "license": "Apache-2.0", "dependencies": { - "minipass": "^7.0.4" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "devOptional": true, - "license": "MIT", + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.17.0", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "devOptional": true, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } + "optional": true }, - "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==", - "devOptional": true, + "node_modules/@faker-js/faker": { + "version": "10.4.0", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", + "npm": ">=10" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "devOptional": true, - "license": "MIT", + "node_modules/@grpc/grpc-js": { + "version": "1.14.4", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" } }, - "node_modules/@lix-js/sdk": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@lix-js/sdk/-/sdk-0.4.7.tgz", - "integrity": "sha512-pRbW+joG12L0ULfMiWYosIW0plmW4AsUdiPCp+Z8rAsElJ+wJ6in58zhD3UwUcd4BNcpldEGjg6PdA7e0RgsDQ==", + "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "version": "0.8.1", "dev": true, "license": "Apache-2.0", "dependencies": { - "@lix-js/server-protocol-schema": "0.1.1", - "dedent": "1.5.1", - "human-id": "^4.1.1", - "js-sha256": "^0.11.0", - "kysely": "^0.27.4", - "sqlite-wasm-kysely": "0.3.0", - "uuid": "^10.0.0" + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" }, "engines": { - "node": ">=18" + "node": ">=6" } }, - "node_modules/@lix-js/sdk/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, "bin": { - "uuid": "dist/bin/uuid" + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" } }, - "node_modules/@lix-js/server-protocol-schema": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@lix-js/server-protocol-schema/-/server-protocol-schema-0.1.1.tgz", - "integrity": "sha512-jBeALB6prAbtr5q4vTuxnRZZv1M2rKe8iNqRQhFJ4Tv7150unEa0vKyz0hs8Gl3fUGsWaNJBh3J8++fpbrpRBQ==", + "node_modules/@hapi/hoek": { + "version": "9.3.0", "dev": true, - "license": "Apache-2.0" + "license": "BSD-3-Clause", + "optional": true }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.6.tgz", - "integrity": "sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==", - "license": "MIT", - "peer": true, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, "dependencies": { - "sparse-bitfield": "^3.0.3" + "@hapi/hoek": "^9.0.0" } }, - "node_modules/@mrleebo/prisma-ast": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@mrleebo/prisma-ast/-/prisma-ast-0.13.1.tgz", - "integrity": "sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==", - "license": "MIT", - "peer": true, - "dependencies": { - "chevrotain": "^10.5.0", - "lilconfig": "^2.1.0" - }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=16" + "node": ">=18.18.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "node_modules/@humanfs/node": { + "version": "0.16.7", "dev": true, - "license": "MIT", - "optional": true, + "license": "Apache-2.0", "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@noble/ciphers": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.1.1.tgz", - "integrity": "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw==", - "license": "MIT", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 20.19.0" + "node": ">=12.22" }, "funding": { - "url": "https://paulmillr.com/funding/" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@noble/hashes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", - "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@nodable/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/nodable" - } - ], - "license": "MIT" - }, - "node_modules/@npmcli/agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", - "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, + "license": "Apache-2.0", "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@npmcli/fs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", - "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "semver": "^7.3.5" + "node": ">=18.18" }, - "engines": { - "node": "^18.17.0 || >=20.5.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@oozcitak/dom": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", - "integrity": "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==", + "node_modules/@iconify-json/lsicon": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@iconify-json/lsicon/-/lsicon-1.2.5.tgz", + "integrity": "sha512-dXmYFljtE+xYf/QKzs3WYjHjJuJIbagiUsIT5NL5z+qsWrCOHojfoL0inivGSSpGJjRQM18GPjspzzPaTfJVtw==", "dev": true, "license": "MIT", "dependencies": { - "@oozcitak/infra": "^2.0.2", - "@oozcitak/url": "^3.0.0", - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" + "@iconify/types": "*" } }, - "node_modules/@oozcitak/infra": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-2.0.2.tgz", - "integrity": "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==", + "node_modules/@iconify-json/material-icon-theme": { + "version": "1.2.67", + "resolved": "https://registry.npmjs.org/@iconify-json/material-icon-theme/-/material-icon-theme-1.2.67.tgz", + "integrity": "sha512-SouqLxahwVOuIVqED8Spl1wSy3DM7sYwNOPxFW7Eh4hVNqR4L4zTkEXFP4V6bQegkhl9kFWbNGlYKDFjXh92iQ==", "dev": true, "license": "MIT", "dependencies": { - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" + "@iconify/types": "*" } }, - "node_modules/@oozcitak/url": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-3.0.0.tgz", - "integrity": "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==", + "node_modules/@iconify-json/material-symbols": { + "version": "1.2.74", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@oozcitak/infra": "^2.0.2", - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" + "@iconify/types": "*" } }, - "node_modules/@oozcitak/util": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-10.0.0.tgz", - "integrity": "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==", + "node_modules/@iconify-json/vscode-icons": { + "version": "1.2.55", + "resolved": "https://registry.npmjs.org/@iconify-json/vscode-icons/-/vscode-icons-1.2.55.tgz", + "integrity": "sha512-7c6yep/OW7/xVWPedBeFbHv5wM4PnRcrZvlsaB+l5cBNWL/6thNE1yuN+PDPQZoEGdXRMUfwDAI3qF0ZVftwag==", "dev": true, "license": "MIT", - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" + "dependencies": { + "@iconify/types": "*" } }, - "node_modules/@pinojs/redact": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "node_modules/@iconify/types": { + "version": "2.0.0", + "dev": true, "license": "MIT" }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@iconify/utils": { + "version": "3.1.3", "dev": true, "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "node_modules/@inlang/paraglide-js": { + "version": "2.12.0", "dev": true, "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "dependencies": { + "@inlang/recommend-sherlock": "^0.2.1", + "@inlang/sdk": "^2.7.0", + "commander": "11.1.0", + "consola": "3.4.0", + "json5": "2.2.3", + "unplugin": "^2.1.2", + "urlpattern-polyfill": "^10.0.0" }, - "funding": { - "url": "https://opencollective.com/pkgr" + "bin": { + "paraglide-js": "bin/run.js" } }, - "node_modules/@playwright/test": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", - "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "node_modules/@inlang/recommend-sherlock": { + "version": "0.2.1", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "playwright": "1.58.2" - }, - "bin": { - "playwright": "cli.js" + "comment-json": "^4.2.3" + } + }, + "node_modules/@inlang/sdk": { + "version": "2.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@lix-js/sdk": "0.4.7", + "@sinclair/typebox": "^0.31.17", + "kysely": "^0.27.4", + "sqlite-wasm-kysely": "0.3.0", + "uuid": "^13.0.0" }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@poppinss/macroable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@poppinss/macroable/-/macroable-1.1.0.tgz", - "integrity": "sha512-y/YKzZDuG8XrpXpM7Z1RdQpiIc0MAKyva24Ux1PB4aI7RiSI/79K8JVDcdyubriTm7vJ1LhFs8CrZpmPnx/8Pw==", + "node_modules/@inlang/sdk/node_modules/kysely": { + "version": "0.27.6", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz", + "integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==", "dev": true, "license": "MIT", - "optional": true - }, - "node_modules/@prisma/client": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz", - "integrity": "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==", - "hasInstallScript": true, - "license": "Apache-2.0", - "peer": true, "engines": { - "node": ">=16.13" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } + "node": ">=14.0.0" } }, - "node_modules/@prisma/config": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.4.2.tgz", - "integrity": "sha512-CftBjWxav99lzY1Z4oDgomdb1gh9BJFAOmWF6P2v1xRfXqQb56DfBub+QKcERRdNoAzCb3HXy3Zii8Vb4AsXhg==", + "node_modules/@internationalized/date": { + "version": "3.11.0", "license": "Apache-2.0", - "peer": true, "dependencies": { - "c12": "3.1.0", - "deepmerge-ts": "7.1.5", - "effect": "3.18.4", - "empathic": "2.0.0" + "@swc/helpers": "^0.5.0" } }, - "node_modules/@prisma/config/node_modules/c12": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", - "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", - "license": "MIT", - "peer": true, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "license": "ISC", "dependencies": { - "chokidar": "^4.0.3", - "confbox": "^0.2.2", - "defu": "^6.1.4", - "dotenv": "^16.6.1", - "exsolve": "^1.0.7", - "giget": "^2.0.0", - "jiti": "^2.4.2", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "perfect-debounce": "^1.0.0", - "pkg-types": "^2.2.0", - "rc9": "^2.1.2" - }, - "peerDependencies": { - "magicast": "^0.3.5" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, - "peerDependenciesMeta": { - "magicast": { - "optional": true - } - } - }, - "node_modules/@prisma/config/node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=12" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^7.0.4" }, - "funding": { - "url": "https://dotenvx.com" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@prisma/config/node_modules/effect": { - "version": "3.18.4", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", - "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { - "@standard-schema/spec": "^1.0.0", - "fast-check": "^3.23.1" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@prisma/config/node_modules/magicast": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", - "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "devOptional": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "@babel/parser": "^7.25.4", - "@babel/types": "^7.25.4", - "source-map-js": "^1.2.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@prisma/config/node_modules/perfect-debounce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", - "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "devOptional": true, "license": "MIT", - "peer": true - }, - "node_modules/@prisma/debug": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.4.2.tgz", - "integrity": "sha512-aP7qzu+g/JnbF6U69LMwHoUkELiserKmWsE2shYuEpNUJ4GrtxBCvZwCyCBHFSH2kLTF2l1goBlBh4wuvRq62w==", - "license": "Apache-2.0", - "peer": true - }, - "node_modules/@prisma/dev": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.20.0.tgz", - "integrity": "sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ==", - "license": "ISC", - "peer": true, - "dependencies": { - "@electric-sql/pglite": "0.3.15", - "@electric-sql/pglite-socket": "0.0.20", - "@electric-sql/pglite-tools": "0.2.20", - "@hono/node-server": "1.19.9", - "@mrleebo/prisma-ast": "0.13.1", - "@prisma/get-platform": "7.2.0", - "@prisma/query-plan-executor": "7.2.0", - "foreground-child": "3.3.1", - "get-port-please": "3.2.0", - "hono": "4.11.4", - "http-status-codes": "2.3.0", - "pathe": "2.0.3", - "proper-lockfile": "4.1.2", - "remeda": "2.33.4", - "std-env": "3.10.0", - "valibot": "1.2.0", - "zeptomatch": "2.1.0" - } - }, - "node_modules/@prisma/engines": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.4.2.tgz", - "integrity": "sha512-B+ZZhI4rXlzjVqRw/93AothEKOU5/x4oVyJFGo9RpHPnBwaPwk4Pi0Q4iGXipKxeXPs/dqljgNBjK0m8nocOJA==", - "hasInstallScript": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@prisma/debug": "7.4.2", - "@prisma/engines-version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", - "@prisma/fetch-engine": "7.4.2", - "@prisma/get-platform": "7.4.2" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@prisma/engines-version": { - "version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919.tgz", - "integrity": "sha512-5FIKY3KoYQlBuZC2yc16EXfVRQ8HY+fLqgxkYfWCtKhRb3ajCRzP/rPeoSx11+NueJDANdh4hjY36mdmrTcGSg==", - "license": "Apache-2.0", - "peer": true + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "devOptional": true, + "license": "MIT" }, - "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.4.2.tgz", - "integrity": "sha512-UTnChXRwiauzl/8wT4hhe7Xmixja9WE28oCnGpBtRejaHhvekx5kudr3R4Y9mLSA0kqGnAMeyTiKwDVMjaEVsw==", - "license": "Apache-2.0", - "peer": true, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "devOptional": true, + "license": "MIT", "dependencies": { - "@prisma/debug": "7.4.2" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@prisma/fetch-engine": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.4.2.tgz", - "integrity": "sha512-f/c/MwYpdJO7taLETU8rahEstLeXfYgQGlz5fycG7Fbmva3iPdzGmjiSWHeSWIgNnlXnelUdCJqyZnFocurZuA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@prisma/debug": "7.4.2", - "@prisma/engines-version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", - "@prisma/get-platform": "7.4.2" + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" } }, - "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.4.2.tgz", - "integrity": "sha512-UTnChXRwiauzl/8wT4hhe7Xmixja9WE28oCnGpBtRejaHhvekx5kudr3R4Y9mLSA0kqGnAMeyTiKwDVMjaEVsw==", - "license": "Apache-2.0", - "peer": true, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "dev": true, + "license": "MIT", "dependencies": { - "@prisma/debug": "7.4.2" + "debug": "^4.1.1" } }, - "node_modules/@prisma/get-platform": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.2.0.tgz", - "integrity": "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==", + "node_modules/@lix-js/sdk": { + "version": "0.4.7", + "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { - "@prisma/debug": "7.2.0" + "@lix-js/server-protocol-schema": "0.1.1", + "dedent": "1.5.1", + "human-id": "^4.1.1", + "js-sha256": "^0.11.0", + "kysely": "^0.27.4", + "sqlite-wasm-kysely": "0.3.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@prisma/get-platform/node_modules/@prisma/debug": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.2.0.tgz", - "integrity": "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==", - "license": "Apache-2.0", - "peer": true - }, - "node_modules/@prisma/query-plan-executor": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@prisma/query-plan-executor/-/query-plan-executor-7.2.0.tgz", - "integrity": "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==", - "license": "Apache-2.0", - "peer": true + "node_modules/@lix-js/sdk/node_modules/kysely": { + "version": "0.27.6", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz", + "integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } }, - "node_modules/@prisma/studio-core": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.13.1.tgz", - "integrity": "sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg==", - "license": "Apache-2.0", - "peer": true, - "peerDependencies": { - "@types/react": "^18.0.0 || ^19.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node_modules/@lix-js/sdk/node_modules/uuid": { + "version": "10.0.0", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.0.tgz", - "integrity": "sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==", + "node_modules/@lix-js/server-protocol-schema": { + "version": "0.1.1", "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@noble/ciphers": { + "version": "2.1.1", "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "fdir": "^6.2.0", - "is-reference": "1.2.1", - "magic-string": "^0.30.3", - "picomatch": "^4.0.2" - }, "engines": { - "node": ">=16.0.0 || 14 >= 14.17" + "node": ">= 20.19.0" }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0||^4.0.0" + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "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==", + "node_modules/@nodable/entities": { + "version": "2.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.1.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": ">= 8" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", - "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "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": ">= 8" } }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.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": ">= 8" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", - "cpu": [ - "arm" - ], + "node_modules/@npmcli/agent": { + "version": "3.0.0", "dev": true, - "license": "MIT", + "license": "ISC", "optional": true, - "os": [ - "android" - ] + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", - "cpu": [ - "arm64" - ], + "node_modules/@npmcli/fs": { + "version": "4.0.0", "dev": true, - "license": "MIT", + "license": "ISC", "optional": true, - "os": [ - "android" - ] + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", - "cpu": [ - "arm64" - ], + "node_modules/@oozcitak/dom": { + "version": "2.0.2", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "@oozcitak/infra": "^2.0.2", + "@oozcitak/url": "^3.0.0", + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", - "cpu": [ - "x64" - ], + "node_modules/@oozcitak/infra": { + "version": "2.0.2", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", - "cpu": [ - "arm64" - ], + "node_modules/@oozcitak/url": { + "version": "3.0.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "dependencies": { + "@oozcitak/infra": "^2.0.2", + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", - "cpu": [ - "x64" - ], + "node_modules/@oozcitak/util": { + "version": "10.0.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": ">=20.0" + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", - "cpu": [ - "arm" - ], + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", "dev": true, "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">=14" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "node_modules/@pkgr/core": { + "version": "0.2.9", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@playwright/test": { + "version": "1.58.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@poppinss/macroable": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "29.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "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": "16.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "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.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "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/rollup-android-arm-eabi": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "android" ] }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { + "node_modules/@rollup/rollup-android-arm64": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "android" ] }, - "node_modules/@rollup/rollup-linux-arm64-musl": { + "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ] }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { + "node_modules/@rollup/rollup-darwin-x64": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", "cpu": [ - "loong64" + "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ] }, - "node_modules/@rollup/rollup-linux-loong64-musl": { + "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", "cpu": [ - "loong64" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "freebsd" ] }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", "cpu": [ - "ppc64" + "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "freebsd" ] }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2656,7 +2779,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2670,7 +2792,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2684,7 +2805,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2693,12 +2813,9 @@ }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2707,12 +2824,9 @@ }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2726,7 +2840,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2740,7 +2853,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2754,7 +2866,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2768,7 +2879,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2782,7 +2892,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2796,7 +2905,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2805,8 +2913,6 @@ }, "node_modules/@sideway/address": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", - "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", "dev": true, "license": "BSD-3-Clause", "optional": true, @@ -2816,34 +2922,28 @@ }, "node_modules/@sideway/formula": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", "dev": true, "license": "BSD-3-Clause", "optional": true }, "node_modules/@sideway/pinpoint": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", "dev": true, "license": "BSD-3-Clause", "optional": true }, "node_modules/@sinclair/typebox": { "version": "0.31.28", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.31.28.tgz", - "integrity": "sha512-/s55Jujywdw/Jpan+vsy6JZs1z2ZTGxTmbZTPiuSL2wz9mfzA2gN1zzaqmvfi4pq+uOt7Du85fkiwv5ymW84aQ==", "dev": true, "license": "MIT" }, "node_modules/@smithy/core": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.28.0.tgz", - "integrity": "sha512-N/LoLG8pZ1zv5cIWpdF6vmSjtZtXKK9G0OqT5yYCOZU+CzPq1+nYA95VoKJBGWRScs7YbMugZ7lZx8Fj1vdHoA==", + "version": "3.29.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.29.2.tgz", + "integrity": "sha512-DXUk6yU0C1Q1tYvJh1VCtl8QOBcSoZpKwjTPkxT6A4MUQYHvgeKGByL8mrEdxnvhdf9nq5GyzmRb5n/vPgu3Lw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.15.0", + "@smithy/types": "^4.16.0", "tslib": "^2.6.2" }, "engines": { @@ -2852,8 +2952,6 @@ }, "node_modules/@smithy/credential-provider-imds": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.4.tgz", - "integrity": "sha512-vKW0MEFRU4Y3MkVZUkpJm+g9qyPGLCXhc0YLggUdSdBB4g7IaSSsCE75P9rBXyWHrXY1UYSQUl8/DwsTR7QciA==", "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.24.4", @@ -2866,8 +2964,6 @@ }, "node_modules/@smithy/fetch-http-handler": { "version": "5.4.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.4.tgz", - "integrity": "sha512-qM7AUKI4G6d7lNgaZD3lA1tWSolh5r6gcixfTZAPstVURfjIbvreVTPz+994M0yC3HbX4YYhDRgr31Xy3XwWOQ==", "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.24.4", @@ -2880,8 +2976,6 @@ }, "node_modules/@smithy/is-array-buffer": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -2906,8 +3000,6 @@ }, "node_modules/@smithy/signature-v4": { "version": "5.4.4", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.4.tgz", - "integrity": "sha512-e5UtkMvsatzBfbeBZjEOt0k0Z3BEsjTFL/n6fdO5vtBLe67tdy0dX7xw2DU7uZ3acwoHyeCqpU2Fzb7pxwHb6Q==", "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.24.4", @@ -2919,9 +3011,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.15.0.tgz", - "integrity": "sha512-Z5TAOxygoFvybJV3igo5SloFflSokHx2hu1eFA+DxDTcn+FtKxUSui+rbTRG1pAafMA888Z3MVvCWUuvCrTXjg==", + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.0.tgz", + "integrity": "sha512-aVUabzlBBmY0PfvVgLKQSOGFIL5/7R54JE3uD9a5Ay/jSED61SkuAcCYENNXJzYUvJ1NPrWO0P+rAXHCkbBUKw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -2932,8 +3024,6 @@ }, "node_modules/@smithy/util-buffer-from": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", @@ -2945,8 +3035,6 @@ }, "node_modules/@smithy/util-utf8": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", @@ -2958,8 +3046,6 @@ }, "node_modules/@sqlite.org/sqlite-wasm": { "version": "3.48.0-build4", - "resolved": "https://registry.npmjs.org/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.48.0-build4.tgz", - "integrity": "sha512-hI6twvUkzOmyGZhQMza1gpfqErZxXRw6JEsiVjUbo7tFanVD+8Oil0Ih3l2nGzHdxPI41zFmfUQG7GHqhciKZQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2968,14 +3054,10 @@ }, "node_modules/@standard-schema/spec": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "license": "MIT" }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz", - "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -2984,8 +3066,6 @@ }, "node_modules/@sveltejs/adapter-node": { "version": "5.5.3", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.5.3.tgz", - "integrity": "sha512-yeWbKXBL9vqDb/7R8ebvRHeuBHN4cRYYBSquNJSMQtS6rIYkXxsVSveaMTUaLvHYQsb1zNa+nH2iLTOMawBohA==", "dev": true, "license": "MIT", "dependencies": { @@ -3000,8 +3080,6 @@ }, "node_modules/@sveltejs/kit": { "version": "2.53.2", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.53.2.tgz", - "integrity": "sha512-M+MqAvFve12T1HWws/2npP/s3hFtyjw3GB/OXW/8a1jZBk48qnvPJrtgE+VOMc3RnjUMxc4mv/vQ73nvj2uNMg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3042,8 +3120,6 @@ }, "node_modules/@sveltejs/vite-plugin-svelte": { "version": "6.2.4", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.4.tgz", - "integrity": "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3063,8 +3139,6 @@ }, "node_modules/@sveltejs/vite-plugin-svelte-inspector": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.2.tgz", - "integrity": "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3081,8 +3155,6 @@ }, "node_modules/@swc/helpers": { "version": "0.5.18", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz", - "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.0" @@ -3090,8 +3162,6 @@ }, "node_modules/@tailwindcss/node": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", - "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", "dev": true, "license": "MIT", "dependencies": { @@ -3106,8 +3176,6 @@ }, "node_modules/@tailwindcss/oxide": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", - "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", "dev": true, "license": "MIT", "engines": { @@ -3249,8 +3317,6 @@ }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", - "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", "cpu": [ "x64" ], @@ -3266,8 +3332,6 @@ }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", - "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", "cpu": [ "x64" ], @@ -3311,6 +3375,70 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.8.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.8.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", @@ -3347,8 +3475,6 @@ }, "node_modules/@tailwindcss/vite": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", - "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", "dev": true, "license": "MIT", "dependencies": { @@ -3360,10 +3486,16 @@ "vite": "^5.2.0 || ^6 || ^7" } }, + "node_modules/@testcontainers/postgresql": { + "version": "12.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "testcontainers": "^12.0.1" + } + }, "node_modules/@testing-library/svelte-core": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/svelte-core/-/svelte-core-1.0.0.tgz", - "integrity": "sha512-VkUePoLV6oOYwSUvX6ShA8KLnJqZiYMIbP2JW2t0GLWLkJxKGvuH5qrrZBV/X7cXFnLGuFQEC7RheYiZOW68KQ==", "dev": true, "license": "MIT", "engines": { @@ -3373,21 +3505,18 @@ "svelte": "^3 || ^4 || ^5 || ^5.0.0-next.0" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "node_modules/@types/adm-zip": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.8.tgz", + "integrity": "sha512-RVVH7QvZYbN+ihqZ4kX/dMiowf6o+Jk1fNwiSdx0NahBJLU787zkULhGhJM8mf/obmLGmgdMM0bXsQTmyfbR7Q==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@types/node": "*" } }, "node_modules/@types/chai": { "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3397,95 +3526,128 @@ }, "node_modules/@types/cookie": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "devOptional": true, "license": "MIT" }, "node_modules/@types/deep-eql": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "devOptional": true, "license": "MIT" }, + "node_modules/@types/docker-modem": { + "version": "3.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/ssh2": "*" + } + }, + "node_modules/@types/dockerode": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/docker-modem": "*", + "@types/node": "*", + "@types/ssh2": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "devOptional": true, "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "24.10.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.13.tgz", - "integrity": "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~7.16.0" } }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "node_modules/@types/papaparse": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.5.2.tgz", + "integrity": "sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/pg": { + "version": "8.20.0", + "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { - "csstype": "^3.2.2" + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" } }, "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, "license": "MIT" }, + "node_modules/@types/ssh2": { + "version": "1.15.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^18.11.18" + } + }, + "node_modules/@types/ssh2-streams": { + "version": "0.1.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ssh2/node_modules/@types/node": { + "version": "18.19.130", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/ssh2/node_modules/undici-types": { + "version": "5.26.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tar-stream": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-3.1.4.tgz", + "integrity": "sha512-921gW0+g29mCJX0fRvqeHzBlE/XclDaAG0Ousy1LCghsOhvaKacDeRGEVzQP9IPfKn8Vysy7FEXAIxycpc/CMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "devOptional": true, "license": "MIT" }, "node_modules/@types/validator": { "version": "13.15.10", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", - "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", "dev": true, "license": "MIT", "optional": true }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", - "license": "MIT", - "peer": true - }, - "node_modules/@types/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/webidl-conversions": "*" - } - }, "node_modules/@typeschema/class-validator": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@typeschema/class-validator/-/class-validator-0.3.0.tgz", - "integrity": "sha512-OJSFeZDIQ8EK1HTljKLT5CItM2wsbgczLN8tMEfz3I1Lmhc5TBfkZ0eikFzUC16tI3d1Nag7um6TfCgp2I2Bww==", "dev": true, "license": "MIT", "optional": true, @@ -3503,8 +3665,6 @@ }, "node_modules/@typeschema/core": { "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@typeschema/core/-/core-0.14.0.tgz", - "integrity": "sha512-Ia6PtZHcL3KqsAWXjMi5xIyZ7XMH4aSnOQes8mfMLx+wGFGtGRNlwe6Y7cYvX+WfNK67OL0/HSe9t8QDygV0/w==", "dev": true, "license": "MIT", "optional": true, @@ -3519,8 +3679,6 @@ }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", - "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", "dev": true, "license": "MIT", "dependencies": { @@ -3548,8 +3706,6 @@ }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { @@ -3558,8 +3714,6 @@ }, "node_modules/@typescript-eslint/parser": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", "dependencies": { @@ -3583,8 +3737,6 @@ }, "node_modules/@typescript-eslint/project-service": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", - "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3605,8 +3757,6 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", - "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "dev": true, "license": "MIT", "dependencies": { @@ -3623,8 +3773,6 @@ }, "node_modules/@typescript-eslint/tsconfig-utils": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", - "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "dev": true, "license": "MIT", "engines": { @@ -3640,8 +3788,6 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", - "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", "dev": true, "license": "MIT", "dependencies": { @@ -3665,8 +3811,6 @@ }, "node_modules/@typescript-eslint/types": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true, "license": "MIT", "engines": { @@ -3679,8 +3823,6 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", - "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "dev": true, "license": "MIT", "dependencies": { @@ -3707,8 +3849,6 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", "engines": { @@ -3716,9 +3856,7 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", "dev": true, "license": "MIT", "dependencies": { @@ -3730,8 +3868,6 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -3746,8 +3882,6 @@ }, "node_modules/@typescript-eslint/utils": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", - "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", "dev": true, "license": "MIT", "dependencies": { @@ -3770,8 +3904,6 @@ }, "node_modules/@typescript-eslint/visitor-keys": { "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", - "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "dev": true, "license": "MIT", "dependencies": { @@ -3788,8 +3920,6 @@ }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -3801,8 +3931,6 @@ }, "node_modules/@valibot/to-json-schema": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@valibot/to-json-schema/-/to-json-schema-1.5.0.tgz", - "integrity": "sha512-GE7DmSr1C2UCWPiV0upRH6mv0cCPsqYGs819fb6srCS1tWhyXrkGGe+zxUiwzn/L1BOfADH4sNjY/YHCuP8phQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -3811,8 +3939,6 @@ }, "node_modules/@vinejs/compiler": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@vinejs/compiler/-/compiler-3.0.0.tgz", - "integrity": "sha512-v9Lsv59nR56+bmy2p0+czjZxsLHwaibJ+SV5iK9JJfehlJMa501jUJQqqz4X/OqKXrxtE3uTQmSqjUqzF3B2mw==", "dev": true, "license": "MIT", "optional": true, @@ -3822,8 +3948,6 @@ }, "node_modules/@vinejs/vine": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@vinejs/vine/-/vine-3.0.1.tgz", - "integrity": "sha512-ZtvYkYpZOYdvbws3uaOAvTFuvFXoQGAtmzeiXu+XSMGxi5GVsODpoI9Xu9TplEMuD/5fmAtBbKb9cQHkWkLXDQ==", "dev": true, "license": "MIT", "optional": true, @@ -3843,9 +3967,7 @@ }, "node_modules/@vitest/browser": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.0.18.tgz", - "integrity": "sha512-gVQqh7paBz3gC+ZdcCmNSWJMk70IUjDeVqi+5m5vYpEHsIwRgw3Y545jljtajhkekIpIp5Gg8oK7bctgY0E2Ng==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/mocker": "4.0.18", @@ -3866,9 +3988,7 @@ }, "node_modules/@vitest/browser-playwright": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.0.18.tgz", - "integrity": "sha512-gfajTHVCiwpxRj1qh0Sh/5bbGLG4F/ZH/V9xvFVoFddpITfMta9YGow0W6ZpTTORv2vdJuz9TnrNSmjKvpOf4g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/browser": "4.0.18", @@ -3890,8 +4010,6 @@ }, "node_modules/@vitest/coverage-v8": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", "dev": true, "license": "MIT", "dependencies": { @@ -3921,8 +4039,6 @@ }, "node_modules/@vitest/expect": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3939,8 +4055,6 @@ }, "node_modules/@vitest/mocker": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3966,8 +4080,6 @@ }, "node_modules/@vitest/mocker/node_modules/estree-walker": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3976,8 +4088,6 @@ }, "node_modules/@vitest/pretty-format": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3989,8 +4099,6 @@ }, "node_modules/@vitest/runner": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -4003,8 +4111,6 @@ }, "node_modules/@vitest/snapshot": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -4018,8 +4124,6 @@ }, "node_modules/@vitest/spy": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", "devOptional": true, "license": "MIT", "funding": { @@ -4028,8 +4132,6 @@ }, "node_modules/@vitest/utils": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -4040,10 +4142,21 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@zerollup/ts-helpers": { + "version": "1.7.18", + "resolved": "https://registry.npmjs.org/@zerollup/ts-helpers/-/ts-helpers-1.7.18.tgz", + "integrity": "sha512-S9zN+y+i5yN/evfWquzSO3lubqPXIsPQf6p9OiPMpRxDx/0totPLF39XoRw48Dav5dSvbIE8D2eAPpXXJxvKwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.12.0" + }, + "peerDependencies": { + "typescript": ">=3.7.2" + } + }, "node_modules/abbrev": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", - "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", "dev": true, "license": "ISC", "optional": true, @@ -4051,10 +4164,19 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, "license": "MIT", "dependencies": { @@ -4067,8 +4189,6 @@ }, "node_modules/acorn": { "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "devOptional": true, "license": "MIT", "bin": { @@ -4080,18 +4200,23 @@ }, "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, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/adm-zip": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", + "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/agent-base": { "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", "optional": true, @@ -4101,8 +4226,6 @@ }, "node_modules/ajv": { "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -4118,8 +4241,6 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, "license": "MIT", "optional": true, @@ -4137,8 +4258,6 @@ }, "node_modules/ajv-formats-draft2019": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ajv-formats-draft2019/-/ajv-formats-draft2019-1.6.1.tgz", - "integrity": "sha512-JQPvavpkWDvIsBp2Z33UkYCtXCSpW4HD3tAZ+oL4iEFOk9obQZffx0yANwECt6vzr6ET+7HN5czRyqXbnq/u0Q==", "dev": true, "license": "MIT", "optional": true, @@ -4154,8 +4273,6 @@ }, "node_modules/ajv-formats/node_modules/ajv": { "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "optional": true, @@ -4172,19 +4289,14 @@ }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT", "optional": true }, "node_modules/ansi-regex": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=12" }, @@ -4194,8 +4306,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -4210,8 +4320,6 @@ }, "node_modules/antlr-ng": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/antlr-ng/-/antlr-ng-1.0.10.tgz", - "integrity": "sha512-fw3NdsQP3dabuZrDhKAMewrBsY5KSAcMrvhWBVDmHYegv5D51pypzCYK1PpjaRVKcVeP/5xKfqJY31TvXACOdA==", "dev": true, "license": "MIT", "dependencies": { @@ -4229,8 +4337,6 @@ }, "node_modules/antlr-ng/node_modules/commander": { "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", "dev": true, "license": "MIT", "engines": { @@ -4239,8 +4345,6 @@ }, "node_modules/antlr4-c3": { "version": "3.4.4", - "resolved": "https://registry.npmjs.org/antlr4-c3/-/antlr4-c3-3.4.4.tgz", - "integrity": "sha512-ixp1i17ypbRzZnffdarIfCVEXJwPydtDt61SHMGkc+UCD7rrbfvHESTMTgx8jFhUgKAgcHyt9060kQ8nU3vlxA==", "license": "MIT", "dependencies": { "antlr4ng": "3.0.16" @@ -4248,31 +4352,189 @@ }, "node_modules/antlr4ng": { "version": "3.0.16", - "resolved": "https://registry.npmjs.org/antlr4ng/-/antlr4ng-3.0.16.tgz", - "integrity": "sha512-DQuJkC7kX3xunfF4K2KsWTSvoxxslv+FQp/WHQZTJSsH2Ec3QfFmrxC3Nky2ok9yglXn6nHM4zUaVDxcN5f6kA==", "license": "BSD-3-Clause" }, - "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==", + "node_modules/archiver": { + "version": "7.0.1", "dev": true, - "license": "Python-2.0" - }, - "node_modules/aria-query": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", - "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", - "devOptional": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, "engines": { - "node": ">= 0.4" + "node": ">= 14" } }, - "node_modules/arkregex": { + "node_modules/archiver-utils": { + "version": "5.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archunit": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/archunit/-/archunit-2.3.3.tgz", + "integrity": "sha512-dc2fCA1PqqHjofrWHk/cLaCVYTvIYtiDB2aQ62L1+LB/4Fw2J8zJRlyjoqVHC4b+MrXIzdq2uAFGNBfqDZrWuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zerollup/ts-helpers": "^1.7.18", + "minimatch": "^10.0.1", + "plantuml-parser": "^0.4.0", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, + "node_modules/archunit/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/archunit/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/archunit/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.1", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arkregex": { "version": "0.0.5", - "resolved": "https://registry.npmjs.org/arkregex/-/arkregex-0.0.5.tgz", - "integrity": "sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==", "dev": true, "license": "MIT", "optional": true, @@ -4282,8 +4544,6 @@ }, "node_modules/arktype": { "version": "2.1.29", - "resolved": "https://registry.npmjs.org/arktype/-/arktype-2.1.29.tgz", - "integrity": "sha512-jyfKk4xIOzvYNayqnD8ZJQqOwcrTOUbIU4293yrzAjA3O1dWh61j71ArMQ6tS/u4pD7vabSPe7nG3RCyoXW6RQ==", "dev": true, "license": "MIT", "optional": true, @@ -4295,15 +4555,19 @@ }, "node_modules/array-timsort": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", - "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", "dev": true, "license": "MIT" }, + "node_modules/asn1": { + "version": "0.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, "node_modules/assertion-error": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "devOptional": true, "license": "MIT", "engines": { @@ -4312,8 +4576,6 @@ }, "node_modules/ast-v8-to-istanbul": { "version": "0.3.12", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.12.tgz", - "integrity": "sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==", "dev": true, "license": "MIT", "dependencies": { @@ -4324,54 +4586,135 @@ }, "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } }, + "node_modules/async": { + "version": "3.2.6", + "dev": true, + "license": "MIT" + }, + "node_modules/async-lock": { + "version": "1.4.1", + "dev": true, + "license": "MIT" + }, "node_modules/atomic-sleep": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", "license": "MIT", "engines": { "node": ">=8.0.0" } }, - "node_modules/aws-ssl-profiles": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", - "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/axobject-query": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" } }, + "node_modules/b4a": { + "version": "1.8.1", + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, "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, "license": "MIT" }, + "node_modules/bare-events": { + "version": "2.9.1", + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.2", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.9.1", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.1", + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.1", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.5", + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -4390,8 +4733,6 @@ }, "node_modules/basic-auth": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, "license": "MIT", "dependencies": { @@ -4401,27 +4742,35 @@ "node": ">= 0.8" } }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, "node_modules/better-auth": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.5.4.tgz", - "integrity": "sha512-ReykcEKx6Kp9560jG1wtlDBnftA7L7xb3ZZdDWm5yGXKKe2pUf+oBjH0fqekrkRII0m4XBVQbQ0mOrFv+3FdYg==", - "license": "MIT", - "dependencies": { - "@better-auth/core": "1.5.4", - "@better-auth/drizzle-adapter": "1.5.4", - "@better-auth/kysely-adapter": "1.5.4", - "@better-auth/memory-adapter": "1.5.4", - "@better-auth/mongo-adapter": "1.5.4", - "@better-auth/prisma-adapter": "1.5.4", - "@better-auth/telemetry": "1.5.4", - "@better-auth/utils": "0.3.1", - "@better-fetch/fetch": "1.1.21", + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.20.tgz", + "integrity": "sha512-fSpGHGRKiGRiYVd3QTQtuVZ8oxpiSe/7ip0Rpvt/Sy8zQbEbVKUPMOhE0gLXg+FjqTUsIo7582hxUYxtEcqUpA==", + "license": "MIT", + "dependencies": { + "@better-auth/core": "1.6.20", + "@better-auth/drizzle-adapter": "1.6.20", + "@better-auth/kysely-adapter": "1.6.20", + "@better-auth/memory-adapter": "1.6.20", + "@better-auth/mongo-adapter": "1.6.20", + "@better-auth/prisma-adapter": "1.6.20", + "@better-auth/telemetry": "1.6.20", + "@better-auth/utils": "0.4.2", + "@better-fetch/fetch": "1.3.1", "@noble/ciphers": "^2.1.1", "@noble/hashes": "^2.0.1", - "better-call": "1.3.2", + "better-call": "1.3.6", "defu": "^6.1.4", "jose": "^6.1.3", - "kysely": "^0.28.11", + "kysely": "^0.28.17 || ^0.29.0", "nanostores": "^1.1.1", "zod": "^4.3.6" }, @@ -4433,7 +4782,7 @@ "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", - "drizzle-orm": ">=0.41.0", + "drizzle-orm": "^0.45.2", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", @@ -4506,114 +4855,13 @@ } } }, - "node_modules/better-auth/node_modules/@better-auth/core": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.5.4.tgz", - "integrity": "sha512-k5AdwPRQETZn0vdB60EB9CDxxfllpJXKqVxTjyXIUSRz7delNGlU0cR/iRP3VfVJwvYR1NbekphBDNo+KGoEzQ==", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "zod": "^4.3.6" - }, - "peerDependencies": { - "@better-auth/utils": "0.3.1", - "@better-fetch/fetch": "1.1.21", - "@cloudflare/workers-types": ">=4", - "better-call": "1.3.2", - "jose": "^6.1.0", - "kysely": "^0.28.5", - "nanostores": "^1.0.1" - }, - "peerDependenciesMeta": { - "@cloudflare/workers-types": { - "optional": true - } - } - }, - "node_modules/better-auth/node_modules/@better-auth/drizzle-adapter": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.5.4.tgz", - "integrity": "sha512-4M4nMAWrDd3TmpV6dONkJjybBVKRZghe5Oj0NNyDEoXubxastQdO7Sb5B54I1rTx5yoMgsqaB+kbJnu/9UgjQg==", - "license": "MIT", - "peerDependencies": { - "@better-auth/core": "1.5.4", - "@better-auth/utils": "^0.3.0", - "drizzle-orm": ">=0.41.0" - } - }, - "node_modules/better-auth/node_modules/@better-auth/kysely-adapter": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@better-auth/kysely-adapter/-/kysely-adapter-1.5.4.tgz", - "integrity": "sha512-DPww7rIfz6Ed7dZlJSW9xMQ42VKaJLB5Cs+pPqd+UHKRyighKjf3VgvMIcAdFPc4olQ0qRHo3+ZJhFlBCxRhxA==", - "license": "MIT", - "peerDependencies": { - "@better-auth/core": "1.5.4", - "@better-auth/utils": "^0.3.0", - "kysely": "^0.27.0 || ^0.28.0" - } - }, - "node_modules/better-auth/node_modules/@better-auth/memory-adapter": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@better-auth/memory-adapter/-/memory-adapter-1.5.4.tgz", - "integrity": "sha512-iiWYut9rbQqiAsgRBtj6+nxanwjapxRgpIJbiS2o81h7b9iclE0AiDA0Foes590gdFQvskNauZcCpuF8ytxthg==", - "license": "MIT", - "peerDependencies": { - "@better-auth/core": "1.5.4", - "@better-auth/utils": "^0.3.0" - } - }, - "node_modules/better-auth/node_modules/@better-auth/mongo-adapter": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@better-auth/mongo-adapter/-/mongo-adapter-1.5.4.tgz", - "integrity": "sha512-ArzJN5Obk6i6+vLK1HpPzLIcsjxZYXPPUvxVU8eyU5HyoUT2MlswWfPQ8UJAKPn0iq/T4PVp/wZcQMhWk1tuNA==", - "license": "MIT", - "peerDependencies": { - "@better-auth/core": "1.5.4", - "@better-auth/utils": "^0.3.0", - "mongodb": "^6.0.0 || ^7.0.0" - } - }, - "node_modules/better-auth/node_modules/@better-auth/prisma-adapter": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@better-auth/prisma-adapter/-/prisma-adapter-1.5.4.tgz", - "integrity": "sha512-ZQTbcBopw/ezjjbNFsfR3CRp0QciC4tJCarAnB5G9fZtUYbDjfY0vZOxIRmU4kI3x755CXQpGqTrkwmXaMRa3w==", - "license": "MIT", - "peerDependencies": { - "@better-auth/core": "1.5.4", - "@better-auth/utils": "^0.3.0", - "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", - "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/better-auth/node_modules/@better-auth/telemetry": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.5.4.tgz", - "integrity": "sha512-mGXTY7Ecxo7uvlMr6TFCBUvlH0NUMOeE9LKgPhG4HyhBN6VfCEg/DD9PG0Z2IatmMWQbckkt7ox5A0eBpG9m5w==", - "license": "MIT", - "dependencies": { - "@better-auth/utils": "0.3.1", - "@better-fetch/fetch": "1.1.21" - }, - "peerDependencies": { - "@better-auth/core": "1.5.4" - } - }, - "node_modules/better-auth/node_modules/kysely": { - "version": "0.28.17", - "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.17.tgz", - "integrity": "sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q==", - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/better-call": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.2.tgz", - "integrity": "sha512-4cZIfrerDsNTn3cm+MhLbUePN0gdwkhSXEuG7r/zuQ8c/H7iU0/jSK5TD3FW7U0MgKHce/8jGpPYNO4Ve+4NBw==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.6.tgz", + "integrity": "sha512-no1jI+h6Bkxs1NVBo4rONbVIzsPjZ8IUu7IHaJBiFwVX1XEQGN8KpHots5fSWmXe9nNyLuLIcgx6WEUcE6EDaA==", "license": "MIT", "dependencies": { - "@better-auth/utils": "^0.3.1", + "@better-auth/utils": "^0.4.0", "@better-fetch/fetch": "^1.1.21", "rou3": "^0.7.12", "set-cookie-parser": "^3.0.1" @@ -4629,8 +4877,6 @@ }, "node_modules/bindings": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, "license": "MIT", "optional": true, @@ -4640,8 +4886,6 @@ }, "node_modules/bintrees": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", - "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", "license": "MIT" }, "node_modules/bl": { @@ -4650,7 +4894,6 @@ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -4659,8 +4902,6 @@ }, "node_modules/body-parser": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "dev": true, "license": "MIT", "dependencies": { @@ -4684,14 +4925,10 @@ }, "node_modules/bowser": { "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", "dev": true, "license": "MIT", "dependencies": { @@ -4699,46 +4936,58 @@ "concat-map": "0.0.1" } }, - "node_modules/bson": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz", - "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==", - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=20.19.0" - } + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } }, "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "version": "5.6.0", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/buffer-crc32": { + "version": "1.0.0", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "devOptional": true, + "license": "MIT" + }, + "node_modules/buildcheck": { + "version": "0.0.7", + "dev": true, "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/byline": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "license": "MIT", "engines": { @@ -4747,8 +4996,6 @@ }, "node_modules/cacache": { "version": "19.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", - "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", "dev": true, "license": "ISC", "optional": true, @@ -4772,8 +5019,6 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4786,8 +5031,6 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { @@ -4803,8 +5046,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", "engines": { @@ -4813,8 +5054,6 @@ }, "node_modules/camelcase": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", - "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", "dev": true, "license": "MIT", "optional": true, @@ -4827,8 +5066,6 @@ }, "node_modules/chai": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "devOptional": true, "license": "MIT", "engines": { @@ -4837,8 +5074,6 @@ }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -4852,25 +5087,9 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chevrotain": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.5.0.tgz", - "integrity": "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@chevrotain/cst-dts-gen": "10.5.0", - "@chevrotain/gast": "10.5.0", - "@chevrotain/types": "10.5.0", - "@chevrotain/utils": "10.5.0", - "lodash": "4.17.21", - "regexp-to-ast": "0.5.0" - } - }, "node_modules/chokidar": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -4884,26 +5103,11 @@ }, "node_modules/chownr": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/citty": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", - "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "consola": "^3.2.3" - } + "license": "ISC" }, "node_modules/class-validator": { "version": "0.14.4", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.4.tgz", - "integrity": "sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==", "dev": true, "license": "MIT", "optional": true, @@ -4913,10 +5117,74 @@ "validator": "^13.15.22" } }, + "node_modules/cliui": { + "version": "8.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clsx": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "devOptional": true, "license": "MIT", "engines": { @@ -4925,8 +5193,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -4938,22 +5204,16 @@ }, "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==", "dev": true, "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true, "license": "MIT" }, "node_modules/commander": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, "license": "MIT", "engines": { @@ -4962,8 +5222,6 @@ }, "node_modules/comment-json": { "version": "4.5.1", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.5.1.tgz", - "integrity": "sha512-taEtr3ozUmOB7it68Jll7s0Pwm+aoiHyXKrEC8SEodL4rNpdfDLqa7PfBlrgFoCNNdR8ImL+muti5IGvktJAAg==", "dev": true, "license": "MIT", "dependencies": { @@ -4977,28 +5235,75 @@ }, "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, "license": "MIT" }, + "node_modules/compress-commons": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/compress-commons/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.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, "license": "MIT" }, "node_modules/confbox": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", - "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true, "license": "MIT" }, "node_modules/consola": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", - "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "dev": true, "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" @@ -5006,8 +5311,6 @@ }, "node_modules/content-disposition": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", "engines": { @@ -5020,8 +5323,6 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "license": "MIT", "engines": { @@ -5030,8 +5331,6 @@ }, "node_modules/cookie": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "devOptional": true, "license": "MIT", "engines": { @@ -5040,8 +5339,6 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "dev": true, "license": "MIT", "engines": { @@ -5050,15 +5347,11 @@ }, "node_modules/core-util-is": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true, "license": "MIT" }, "node_modules/cors": { "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "dev": true, "license": "MIT", "dependencies": { @@ -5073,10 +5366,83 @@ "url": "https://opencollective.com/express" } }, + "node_modules/cpu-features": { + "version": "0.0.10", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "buildcheck": "~0.0.6", + "nan": "^2.19.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/crc32-stream/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -5089,8 +5455,6 @@ }, "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, "license": "MIT", "bin": { @@ -5100,17 +5464,8 @@ "node": ">=4" } }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT", - "peer": true - }, "node_modules/daisyui": { "version": "5.5.19", - "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.19.tgz", - "integrity": "sha512-pbFAkl1VCEh/MPCeclKL61I/MqRIFFhNU7yiXoDDRapXN4/qNCoMxeCCswyxEEhqL5eiTTfwHvucFtOE71C9sA==", "dev": true, "license": "MIT", "funding": { @@ -5119,8 +5474,6 @@ }, "node_modules/dateformat": { "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", "dev": true, "license": "MIT", "engines": { @@ -5129,16 +5482,12 @@ }, "node_modules/dayjs": { "version": "1.11.19", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", "dev": true, "license": "MIT", "optional": true }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { @@ -5155,8 +5504,6 @@ }, "node_modules/decompress-response": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, "license": "MIT", "optional": true, @@ -5172,8 +5519,6 @@ }, "node_modules/dedent": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -5187,8 +5532,6 @@ }, "node_modules/deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "license": "MIT", "optional": true, @@ -5198,69 +5541,32 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/deepmerge-ts": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", - "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/defu": { "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "license": "MIT" }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/destr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", - "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", - "license": "MIT", - "peer": true - }, "node_modules/detect-libc": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -5268,42 +5574,86 @@ }, "node_modules/devalue": { "version": "5.6.3", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz", - "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==", "devOptional": true, "license": "MIT" }, "node_modules/discontinuous-range": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", - "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", "dev": true, "license": "MIT", "optional": true }, "node_modules/dlv": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true, "license": "MIT", "optional": true }, + "node_modules/docker-compose": { + "version": "1.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "yaml": "^2.2.2" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/docker-modem": { + "version": "5.0.7", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.1", + "readable-stream": "^3.5.0", + "split-ca": "^1.0.1", + "ssh2": "^1.15.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/dockerode": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "@grpc/grpc-js": "^1.11.1", + "@grpc/proto-loader": "^0.7.13", + "docker-modem": "^5.0.7", + "protobufjs": "^7.3.2", + "tar-fs": "^2.1.4" + }, + "engines": { + "node": ">= 14.17" + } + }, "node_modules/dompurify": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", - "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, - "node_modules/drizzle-orm": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.41.0.tgz", - "integrity": "sha512-7A4ZxhHk9gdlXmTdPj/lREtP+3u8KvZ4yEN6MYVxBzZGex5Wtdc+CWSbu7btgF6TB0N+MNPrvW7RKBbxJchs/Q==", + "node_modules/drizzle-kit": { + "version": "0.31.10", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@drizzle-team/brocli": "^0.10.2", + "@esbuild-kit/esm-loader": "^2.5.5", + "esbuild": "^0.25.4", + "tsx": "^4.21.0" + }, + "bin": { + "drizzle-kit": "bin.cjs" + } + }, + "node_modules/drizzle-orm": { + "version": "0.45.2", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", @@ -5313,12 +5663,13 @@ "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", - "@planetscale/database": ">=1", + "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", + "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", @@ -5376,6 +5727,9 @@ "@types/sql.js": { "optional": true }, + "@upstash/redis": { + "optional": true + }, "@vercel/postgres": { "optional": true }, @@ -5422,8 +5776,6 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { @@ -5435,25 +5787,54 @@ "node": ">= 0.4" } }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true, "license": "MIT" }, "node_modules/effect": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.21.2.tgz", - "integrity": "sha512-rXd2FGDM8KdjSIrc+mqEELo7ScW7xTVxEf1iInmPSpIde9/nyGuFM710cjTo7/EreGXiUX2MOonPpprbz2XHCg==", + "version": "3.21.3", "dev": true, "license": "MIT", "optional": true, @@ -5464,26 +5845,11 @@ }, "node_modules/emoji-regex": { "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/empathic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", - "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=14" - } + "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -5492,8 +5858,6 @@ }, "node_modules/encoding": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dev": true, "license": "MIT", "optional": true, @@ -5503,8 +5867,6 @@ }, "node_modules/encoding/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, "license": "MIT", "optional": true, @@ -5517,8 +5879,6 @@ }, "node_modules/end-of-stream": { "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "dev": true, "license": "MIT", "dependencies": { @@ -5527,8 +5887,6 @@ }, "node_modules/enhanced-resolve": { "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "dev": true, "license": "MIT", "dependencies": { @@ -5541,8 +5899,6 @@ }, "node_modules/env-paths": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, "license": "MIT", "optional": true, @@ -5552,16 +5908,12 @@ }, "node_modules/err-code": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true, "license": "MIT", "optional": true }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", "engines": { @@ -5570,8 +5922,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -5580,15 +5930,11 @@ }, "node_modules/es-module-lexer": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "devOptional": true, "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", "dependencies": { @@ -5599,10 +5945,8 @@ } }, "node_modules/esbuild": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", - "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", - "dev": true, + "version": "0.25.12", + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -5612,970 +5956,533 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.2", - "@esbuild/android-arm": "0.28.2", - "@esbuild/android-arm64": "0.28.2", - "@esbuild/android-x64": "0.28.2", - "@esbuild/darwin-arm64": "0.28.2", - "@esbuild/darwin-x64": "0.28.2", - "@esbuild/freebsd-arm64": "0.28.2", - "@esbuild/freebsd-x64": "0.28.2", - "@esbuild/linux-arm": "0.28.2", - "@esbuild/linux-arm64": "0.28.2", - "@esbuild/linux-ia32": "0.28.2", - "@esbuild/linux-loong64": "0.28.2", - "@esbuild/linux-mips64el": "0.28.2", - "@esbuild/linux-ppc64": "0.28.2", - "@esbuild/linux-riscv64": "0.28.2", - "@esbuild/linux-s390x": "0.28.2", - "@esbuild/linux-x64": "0.28.2", - "@esbuild/netbsd-arm64": "0.28.2", - "@esbuild/netbsd-x64": "0.28.2", - "@esbuild/openbsd-arm64": "0.28.2", - "@esbuild/openbsd-x64": "0.28.2", - "@esbuild/openharmony-arm64": "0.28.2", - "@esbuild/sunos-x64": "0.28.2", - "@esbuild/win32-arm64": "0.28.2", - "@esbuild/win32-ia32": "0.28.2", - "@esbuild/win32-x64": "0.28.2" - } - }, - "node_modules/esbuild/node_modules/@esbuild/aix-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", - "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", - "cpu": [ - "ppc64" - ], + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], "engines": { - "node": ">=18" + "node": ">=6" } }, - "node_modules/esbuild/node_modules/@esbuild/android-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", - "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", - "cpu": [ - "arm" - ], + "node_modules/escape-html": { + "version": "1.0.3", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/esbuild/node_modules/@esbuild/android-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", - "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", - "cpu": [ - "arm64" - ], + "node_modules/escape-string-regexp": { + "version": "4.0.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esbuild/node_modules/@esbuild/android-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", - "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", - "cpu": [ - "x64" - ], + "node_modules/eslint": { + "version": "9.39.2", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/esbuild/node_modules/@esbuild/darwin-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", - "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", - "cpu": [ - "arm64" - ], + "node_modules/eslint-config-prettier": { + "version": "10.1.8", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/esbuild/node_modules/@esbuild/darwin-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", - "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", - "cpu": [ - "x64" - ], + "node_modules/eslint-plugin-better-tailwindcss": { + "version": "4.3.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@eslint/css-tree": "^3.6.8", + "@valibot/to-json-schema": "^1.5.0", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "synckit": "^0.11.12", + "tailwind-csstree": "^0.1.4", + "tsconfig-paths-webpack-plugin": "^4.2.0", + "valibot": "^1.2.0" + }, "engines": { - "node": ">=18" + "node": "^20.19.0 || ^22.12.0 || >=23.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", + "oxlint": "^1.35.0", + "tailwindcss": "^3.3.0 || ^4.1.17" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "oxlint": { + "optional": true + } } }, - "node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", - "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", - "cpu": [ - "arm64" - ], + "node_modules/eslint-plugin-security": { + "version": "4.0.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "Apache-2.0", + "dependencies": { + "safe-regex": "^2.1.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/esbuild/node_modules/@esbuild/freebsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", - "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", - "cpu": [ - "x64" - ], + "node_modules/eslint-plugin-svelte": { + "version": "3.15.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.6.1", + "@jridgewell/sourcemap-codec": "^1.5.0", + "esutils": "^2.0.3", + "globals": "^16.0.0", + "known-css-properties": "^0.37.0", + "postcss": "^8.4.49", + "postcss-load-config": "^3.1.4", + "postcss-safe-parser": "^7.0.0", + "semver": "^7.6.3", + "svelte-eslint-parser": "^1.4.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": "^8.57.1 || ^9.0.0 || ^10.0.0", + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } } }, - "node_modules/esbuild/node_modules/@esbuild/linux-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", - "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", - "cpu": [ - "arm" - ], + "node_modules/eslint-scope": { + "version": "8.4.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/esbuild/node_modules/@esbuild/linux-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", - "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", - "cpu": [ - "arm64" - ], + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/esbuild/node_modules/@esbuild/linux-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", - "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", - "cpu": [ - "ia32" - ], + "node_modules/eslint/node_modules/@eslint/core": { + "version": "0.17.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", - "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", - "cpu": [ - "loong64" - ], + "node_modules/esm-env": { + "version": "1.2.2", + "devOptional": true, + "license": "MIT" + }, + "node_modules/espree": { + "version": "10.4.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/esbuild/node_modules/@esbuild/linux-mips64el": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", - "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", - "cpu": [ - "mips64el" - ], + "node_modules/esprima": { + "version": "4.0.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, "engines": { - "node": ">=18" + "node": ">=4" } }, - "node_modules/esbuild/node_modules/@esbuild/linux-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", - "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", - "cpu": [ - "ppc64" - ], + "node_modules/esquery": { + "version": "1.7.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, "engines": { - "node": ">=18" + "node": ">=0.10" } }, - "node_modules/esbuild/node_modules/@esbuild/linux-riscv64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", - "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", - "cpu": [ - "riscv64" - ], - "dev": true, + "node_modules/esrap": { + "version": "2.2.3", + "devOptional": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" } }, - "node_modules/esbuild/node_modules/@esbuild/linux-s390x": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", - "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", - "cpu": [ - "s390x" - ], + "node_modules/esrecurse": { + "version": "4.3.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=18" + "node": ">=4.0" } }, - "node_modules/esbuild/node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", - "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", - "cpu": [ - "arm64" - ], + "node_modules/estraverse": { + "version": "5.3.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "license": "BSD-2-Clause", "engines": { - "node": ">=18" + "node": ">=4.0" } }, - "node_modules/esbuild/node_modules/@esbuild/netbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", - "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", - "cpu": [ - "x64" - ], + "node_modules/estree-walker": { + "version": "2.0.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/esbuild/node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", - "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", - "cpu": [ - "arm64" - ], + "node_modules/esutils": { + "version": "2.0.3", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "BSD-2-Clause", "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/esbuild/node_modules/@esbuild/openbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", - "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", - "cpu": [ - "x64" - ], + "node_modules/etag": { + "version": "1.8.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], "engines": { - "node": ">=18" + "node": ">= 0.6" } }, - "node_modules/esbuild/node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", - "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", - "cpu": [ - "arm64" - ], + "node_modules/event-target-shim": { + "version": "5.0.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], "engines": { - "node": ">=18" + "node": ">=6" } }, - "node_modules/esbuild/node_modules/@esbuild/sunos-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", - "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/events": { + "version": "3.3.0", "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], "engines": { - "node": ">=18" + "node": ">=0.8.x" } }, - "node_modules/esbuild/node_modules/@esbuild/win32-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", - "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "node_modules/events-universal": { + "version": "1.0.1", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" } }, - "node_modules/esbuild/node_modules/@esbuild/win32-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", - "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", - "cpu": [ - "ia32" - ], + "node_modules/expand-template": { + "version": "2.0.3", "dev": true, - "license": "MIT", + "license": "(MIT OR WTFPL)", "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=18" + "node": ">=6" } }, - "node_modules/esbuild/node_modules/@esbuild/win32-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", - "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/expect-type": { + "version": "1.3.0", + "devOptional": true, + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=12.0.0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "node_modules/exponential-backoff": { + "version": "3.1.3", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "optional": true }, - "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==", + "node_modules/express": { + "version": "5.2.1", "dev": true, "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, "engines": { - "node": ">=10" + "node": ">= 18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "node_modules/express/node_modules/cookie": { + "version": "0.7.2", "dev": true, "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "node": ">= 0.6" } }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "node_modules/exsolve": { + "version": "1.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", "dev": true, "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } + "optional": true }, - "node_modules/eslint-plugin-better-tailwindcss": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-better-tailwindcss/-/eslint-plugin-better-tailwindcss-4.3.0.tgz", - "integrity": "sha512-AYNFAeqExOS/yt1qn7kg1il0VZvAxGwBuW/6xAQtmKDRZXkdkWzwWCYF6Ou2/0tza42K8xh4q420DBq+QvXzjA==", + "node_modules/fast-check": { + "version": "3.23.2", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], "license": "MIT", + "optional": true, "dependencies": { - "@eslint/css-tree": "^3.6.8", - "@valibot/to-json-schema": "^1.5.0", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "synckit": "^0.11.12", - "tailwind-csstree": "^0.1.4", - "tsconfig-paths-webpack-plugin": "^4.2.0", - "valibot": "^1.2.0" + "pure-rand": "^6.1.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", - "oxlint": "^1.35.0", - "tailwindcss": "^3.3.0 || ^4.1.17" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "oxlint": { - "optional": true - } + "node": ">=8.0.0" } }, - "node_modules/eslint-plugin-security": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-4.0.0.tgz", - "integrity": "sha512-tfuQT8K/Li1ZxhFzyD8wPIKtlzZxqBcPr9q0jFMQ77wWAbKBVEhaMPVQRTMTvCMUDhwBe5vPVqQPwAGk/ASfxQ==", + "node_modules/fast-copy": { + "version": "4.0.2", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-regex": "^2.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } + "license": "MIT" }, - "node_modules/eslint-plugin-svelte": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.15.0.tgz", - "integrity": "sha512-QKB7zqfuB8aChOfBTComgDptMf2yxiJx7FE04nneCmtQzgTHvY8UJkuh8J2Rz7KB9FFV9aTHX6r7rdYGvG8T9Q==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.6.1", - "@jridgewell/sourcemap-codec": "^1.5.0", - "esutils": "^2.0.3", - "globals": "^16.0.0", - "known-css-properties": "^0.37.0", - "postcss": "^8.4.49", - "postcss-load-config": "^3.1.4", - "postcss-safe-parser": "^7.0.0", - "semver": "^7.6.3", - "svelte-eslint-parser": "^1.4.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "eslint": "^8.57.1 || ^9.0.0 || ^10.0.0", - "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "svelte": { - "optional": true - } + "node": ">=8.6.0" } }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "is-glob": "^4.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 6" } }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } + "license": "MIT" }, - "node_modules/eslint/node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "node_modules/fast-levenshtein": { + "version": "2.0.6", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/esm-env": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", - "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "devOptional": true, "license": "MIT" }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "node_modules/fast-printf": { + "version": "1.6.10", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, + "license": "BSD-3-Clause", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrap": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.3.tgz", - "integrity": "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "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, - "license": "BSD-2-Clause", - "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, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "license": "(MIT OR WTFPL)", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "devOptional": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", - "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", - "dev": true, - "license": "Apache-2.0", - "optional": true - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/exsolve": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", - "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", - "license": "MIT" - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/fast-check": { - "version": "3.23.2", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", - "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", - "dependencies": { - "pure-rand": "^6.1.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fast-copy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz", - "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-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, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-printf": { - "version": "1.6.10", - "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.10.tgz", - "integrity": "sha512-GwTgG9O4FVIdShhbVF3JxOgSBY2+ePGsu2V/UONgoCPzF9VY6ZdBMKsHKCYQHZwNk3qNouUolRDsgVxcVA5G1w==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=10.0" + "node": ">=10.0" } }, "node_modules/fast-safe-stringify": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "dev": true, "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "dev": true, "funding": [ { @@ -6592,8 +6499,6 @@ }, "node_modules/fast-xml-builder": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", - "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "funding": [ { "type": "github", @@ -6608,8 +6513,6 @@ }, "node_modules/fast-xml-parser": { "version": "5.7.3", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", - "integrity": "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==", "funding": [ { "type": "github", @@ -6627,10 +6530,18 @@ "fxparser": "src/cli/cli.js" } }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fdir": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "devOptional": true, "license": "MIT", "engines": { @@ -6647,8 +6558,6 @@ }, "node_modules/file-entry-cache": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6660,16 +6569,25 @@ }, "node_modules/file-uri-to-path": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "dev": true, "license": "MIT", "optional": true }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { @@ -6690,8 +6608,6 @@ }, "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, "license": "MIT", "dependencies": { @@ -6707,8 +6623,6 @@ }, "node_modules/flat-cache": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { @@ -6721,15 +6635,12 @@ }, "node_modules/flatted": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC" }, "node_modules/foreground-child": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -6744,8 +6655,6 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, "license": "MIT", "engines": { @@ -6754,8 +6663,6 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, "license": "MIT", "engines": { @@ -6767,13 +6674,10 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/fs-minipass": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, "license": "ISC", "optional": true, @@ -6788,7 +6692,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -6801,8 +6704,6 @@ }, "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==", "dev": true, "license": "MIT", "funding": { @@ -6811,24 +6712,18 @@ }, "node_modules/fzstd": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/fzstd/-/fzstd-0.1.1.tgz", - "integrity": "sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA==", "license": "MIT" }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "is-property": "^1.0.2" + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6850,17 +6745,19 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-port-please": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz", - "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==", + "node_modules/get-port": { + "version": "7.2.0", + "dev": true, "license": "MIT", - "peer": true + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", "dependencies": { @@ -6871,40 +6768,40 @@ "node": ">= 0.4" } }, - "node_modules/giget": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", - "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "citty": "^0.1.6", - "consola": "^3.4.0", - "defu": "^6.1.4", - "node-fetch-native": "^1.6.6", - "nypm": "^0.6.0", - "pathe": "^2.0.3" + "engines": { + "node": ">=10" }, - "bin": { - "giget": "dist/cli.mjs" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "node_modules/get-tsconfig": { + "version": "4.14.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", "dev": true, "license": "MIT", "optional": true }, "node_modules/glob": { "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", - "optional": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -6922,8 +6819,6 @@ }, "node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", "dependencies": { @@ -6934,23 +6829,17 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.1", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", - "optional": true, "dependencies": { "brace-expansion": "^2.0.2" }, @@ -6963,8 +6852,6 @@ }, "node_modules/globals": { "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "license": "MIT", "engines": { @@ -6976,8 +6863,6 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", "engines": { @@ -6989,28 +6874,11 @@ }, "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, "license": "ISC" }, - "node_modules/grammex": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.12.tgz", - "integrity": "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==", - "license": "MIT", - "peer": true - }, - "node_modules/graphmatch": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.1.tgz", - "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==", - "license": "MIT", - "peer": true - }, "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==", "dev": true, "license": "MIT", "engines": { @@ -7019,8 +6887,6 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -7032,8 +6898,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7045,8 +6909,6 @@ }, "node_modules/he": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "license": "MIT", "bin": { @@ -7055,25 +6917,11 @@ }, "node_modules/help-me": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", "dev": true, "license": "MIT" }, - "node_modules/hono": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.4.tgz", - "integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16.9.0" - } - }, "node_modules/hosted-git-info": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", - "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", "dev": true, "license": "ISC", "dependencies": { @@ -7084,9 +6932,7 @@ } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "version": "11.5.1", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -7095,23 +6941,17 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, "license": "MIT" }, "node_modules/http-cache-semantics": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true, "license": "BSD-2-Clause", "optional": true }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7131,8 +6971,6 @@ }, "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, "license": "MIT", "optional": true, @@ -7144,17 +6982,8 @@ "node": ">= 14" } }, - "node_modules/http-status-codes": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", - "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", - "license": "MIT", - "peer": true - }, "node_modules/https-proxy-agent": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "optional": true, @@ -7168,8 +6997,6 @@ }, "node_modules/human-id": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.3.tgz", - "integrity": "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==", "dev": true, "license": "MIT", "bin": { @@ -7178,14 +7005,10 @@ }, "node_modules/hyparquet": { "version": "1.26.0", - "resolved": "https://registry.npmjs.org/hyparquet/-/hyparquet-1.26.0.tgz", - "integrity": "sha512-yxUiViPZ+z5h+xdX4rA1G+k30jXoEsG9I2xEpjaM84imGznbKjZzxuZFsdzqg6C4LxNnnAlDFvzpk4uxQWTbTQ==", "license": "MIT" }, "node_modules/hyparquet-compressors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/hyparquet-compressors/-/hyparquet-compressors-1.1.1.tgz", - "integrity": "sha512-yx7aA3Rhj0YycbdV71+XznQSLAefa4cT0urpgNXy4aM6eSeCknaVDNne8y45Uz74Fb15yyXUzOStlceOJBan7A==", "license": "MIT", "dependencies": { "fzstd": "0.1.1", @@ -7194,14 +7017,11 @@ }, "node_modules/hysnappy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hysnappy/-/hysnappy-1.0.0.tgz", - "integrity": "sha512-MNrC4NfwDGPb889O6gIfEtbvEZCSWUsSEhsz4Oq2FRcpGtXHfeVz3KciSPp5Pnnz1NjFMgDQNfxdJozymJEDDA==", "license": "MIT" }, "node_modules/iconv-lite": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -7216,8 +7036,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -7236,8 +7054,6 @@ }, "node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -7246,8 +7062,6 @@ }, "node_modules/import-fresh": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7263,8 +7077,6 @@ }, "node_modules/import-meta-resolve": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", "dev": true, "license": "MIT", "funding": { @@ -7274,8 +7086,6 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", "engines": { @@ -7284,22 +7094,17 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true, "license": "ISC", "optional": true }, "node_modules/ip-address": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -7308,8 +7113,6 @@ }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, "license": "MIT", "engines": { @@ -7318,8 +7121,6 @@ }, "node_modules/is-core-module": { "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { @@ -7334,8 +7135,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", "engines": { @@ -7344,19 +7143,14 @@ }, "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==", "dev": true, "license": "MIT", - "optional": true, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -7368,15 +7162,21 @@ }, "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, "license": "MIT" }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "license": "MIT", "engines": { @@ -7388,38 +7188,40 @@ }, "node_modules/is-promise": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true, "license": "MIT" }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", - "license": "MIT", - "peer": true - }, "node_modules/is-reference": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -7428,8 +7230,6 @@ }, "node_modules/istanbul-lib-report": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -7443,8 +7243,6 @@ }, "node_modules/istanbul-reports": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -7457,11 +7255,8 @@ }, "node_modules/jackspeak": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", - "optional": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -7474,8 +7269,7 @@ }, "node_modules/jiti": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -7483,8 +7277,6 @@ }, "node_modules/joi": { "version": "17.13.3", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", - "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", "dev": true, "license": "BSD-3-Clause", "optional": true, @@ -7498,8 +7290,6 @@ }, "node_modules/jose": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.1.tgz", - "integrity": "sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -7507,8 +7297,6 @@ }, "node_modules/joycon": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", "dev": true, "license": "MIT", "engines": { @@ -7517,22 +7305,16 @@ }, "node_modules/js-sha256": { "version": "0.11.1", - "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.1.tgz", - "integrity": "sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg==", "dev": true, "license": "MIT" }, "node_modules/js-tokens": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -7544,15 +7326,100 @@ }, "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, "license": "MIT" }, + "node_modules/json-colorizer": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json-colorizer/-/json-colorizer-2.2.2.tgz", + "integrity": "sha512-56oZtwV1piXrQnRNTtJeqRv+B9Y/dXAYLqBBaYl/COcUdoZxgLBLAO88+CnkbT6MxNs0c5E9mPBIb2sFcNz3vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "lodash.get": "^4.4.2" + } + }, + "node_modules/json-colorizer/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/json-colorizer/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-colorizer/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/json-colorizer/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/json-schema-to-ts": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", - "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", "dev": true, "license": "MIT", "optional": true, @@ -7566,22 +7433,16 @@ }, "node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, "node_modules/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, "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", "bin": { @@ -7593,8 +7454,6 @@ }, "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, "license": "MIT", "dependencies": { @@ -7603,8 +7462,6 @@ }, "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==", "devOptional": true, "license": "MIT", "engines": { @@ -7613,25 +7470,53 @@ }, "node_modules/known-css-properties": { "version": "0.37.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz", - "integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==", "dev": true, "license": "MIT" }, "node_modules/kysely": { - "version": "0.27.6", - "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz", - "integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==", - "devOptional": true, + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.29.2.tgz", + "integrity": "sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg==", "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=22.0.0" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" } }, "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, "license": "MIT", "dependencies": { @@ -7644,16 +7529,12 @@ }, "node_modules/libphonenumber-js": { "version": "1.12.36", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.36.tgz", - "integrity": "sha512-woWhKMAVx1fzzUnMCyOzglgSgf6/AFHLASdOBcchYCyvWSGWt12imw3iu2hdI5d4dGZRsNWAmWiz37sDKUPaRQ==", "dev": true, "license": "MIT", "optional": true }, "node_modules/libxmljs2": { "version": "0.37.0", - "resolved": "https://registry.npmjs.org/libxmljs2/-/libxmljs2-0.37.0.tgz", - "integrity": "sha512-Xb78V8GZouoZFrq8cCwx7+G3WYOcJG0xb3YUbweSyE4z2EIrQCZMr3Ye/dHn4mESs6YxUMeQeUZm5IXg+iLHog==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -7670,9 +7551,7 @@ }, "node_modules/lightningcss": { "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", - "dev": true, + "devOptional": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -7705,7 +7584,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7726,7 +7604,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7747,7 +7624,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7768,7 +7644,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7789,7 +7664,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7810,7 +7684,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7831,7 +7704,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7847,12 +7719,9 @@ }, "node_modules/lightningcss-linux-x64-gnu": { "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7868,12 +7737,9 @@ }, "node_modules/lightningcss-linux-x64-musl": { "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7894,7 +7760,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7915,7 +7780,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7931,8 +7795,7 @@ }, "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, "license": "MIT", "engines": { "node": ">=10" @@ -7940,8 +7803,6 @@ }, "node_modules/local-pkg": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz", - "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==", "dev": true, "license": "MIT", "dependencies": { @@ -7958,15 +7819,11 @@ }, "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==", "devOptional": true, "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { @@ -7981,53 +7838,39 @@ }, "node_modules/lodash": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT", - "peer": true + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "license": "MIT" }, "node_modules/long": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0", - "peer": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/lru.min": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", - "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", - "license": "MIT", - "peer": true, - "engines": { - "bun": ">=1.0.0", - "deno": ">=1.30.0", - "node": ">=8.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wellwelwel" - } + "license": "ISC" }, "node_modules/luxon": { "version": "3.5.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", - "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", "dev": true, "license": "MIT", "engines": { @@ -8036,8 +7879,6 @@ }, "node_modules/magic-string": { "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8046,8 +7887,6 @@ }, "node_modules/magicast": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", - "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", "dev": true, "license": "MIT", "dependencies": { @@ -8058,8 +7897,6 @@ }, "node_modules/make-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { @@ -8074,8 +7911,6 @@ }, "node_modules/make-fetch-happen": { "version": "14.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", - "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", "dev": true, "license": "ISC", "optional": true, @@ -8098,8 +7933,6 @@ }, "node_modules/marked": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", - "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -8110,8 +7943,6 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", "engines": { @@ -8120,15 +7951,11 @@ }, "node_modules/mdn-data": { "version": "2.23.0", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.23.0.tgz", - "integrity": "sha512-786vq1+4079JSeu2XdcDjrhi/Ry7BWtjDl9WtGPWLiIHb2T66GvIVflZTBoSNZ5JqTtJGYEVMuFA/lbQlMOyDQ==", "dev": true, "license": "CC0-1.0" }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, "license": "MIT", "engines": { @@ -8137,22 +7964,11 @@ }, "node_modules/memoize-weak": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/memoize-weak/-/memoize-weak-1.0.2.tgz", - "integrity": "sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==", "dev": true, "license": "ISC" }, - "node_modules/memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "license": "MIT", - "peer": true - }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "dev": true, "license": "MIT", "engines": { @@ -8162,10 +7978,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", "engines": { @@ -8174,8 +8025,6 @@ }, "node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { @@ -8191,8 +8040,6 @@ }, "node_modules/mimic-response": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, "license": "MIT", "optional": true, @@ -8205,8 +8052,6 @@ }, "node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -8218,8 +8063,6 @@ }, "node_modules/minimist": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { @@ -8228,19 +8071,14 @@ }, "node_modules/minipass": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, "license": "BlueOak-1.0.0", - "optional": true, "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/minipass-collect": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, "license": "ISC", "optional": true, @@ -8253,8 +8091,6 @@ }, "node_modules/minipass-fetch": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", - "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", "dev": true, "license": "MIT", "optional": true, @@ -8272,8 +8108,6 @@ }, "node_modules/minipass-flush": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, "license": "ISC", "optional": true, @@ -8286,8 +8120,6 @@ }, "node_modules/minipass-flush/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "license": "ISC", "optional": true, @@ -8300,16 +8132,12 @@ }, "node_modules/minipass-flush/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, "license": "ISC", "optional": true }, "node_modules/minipass-pipeline": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "dev": true, "license": "ISC", "optional": true, @@ -8322,8 +8150,6 @@ }, "node_modules/minipass-pipeline/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "license": "ISC", "optional": true, @@ -8336,16 +8162,12 @@ }, "node_modules/minipass-pipeline/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, "license": "ISC", "optional": true }, "node_modules/minipass-sized": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, "license": "ISC", "optional": true, @@ -8358,8 +8180,6 @@ }, "node_modules/minipass-sized/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "license": "ISC", "optional": true, @@ -8372,16 +8192,12 @@ }, "node_modules/minipass-sized/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, "license": "ISC", "optional": true }, "node_modules/minizlib": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "dev": true, "license": "MIT", "optional": true, @@ -8392,18 +8208,27 @@ "node": ">= 18" } }, + "node_modules/mkdirp": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/mlly": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", - "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", "dev": true, "license": "MIT", "dependencies": { @@ -8415,15 +8240,11 @@ }, "node_modules/mlly/node_modules/confbox": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", "dev": true, "license": "MIT" }, "node_modules/mlly/node_modules/pkg-types": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8434,87 +8255,20 @@ }, "node_modules/monaco-editor": { "version": "0.55.1", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", - "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", "license": "MIT", "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" } }, - "node_modules/mongodb": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.1.0.tgz", - "integrity": "sha512-kMfnKunbolQYwCIyrkxNJFB4Ypy91pYqua5NargS/f8ODNSJxT03ZU3n1JqL4mCzbSih8tvmMEMLpKTT7x5gCg==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@mongodb-js/saslprep": "^1.3.0", - "bson": "^7.1.1", - "mongodb-connection-string-url": "^7.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.806.0", - "@mongodb-js/zstd": "^7.0.0", - "gcp-metadata": "^7.0.1", - "kerberos": "^7.0.0", - "mongodb-client-encryption": ">=7.0.0 <7.1.0", - "snappy": "^7.3.2", - "socks": "^2.8.6" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.1.tgz", - "integrity": "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@types/whatwg-url": "^13.0.0", - "whatwg-url": "^14.1.0" - }, - "engines": { - "node": ">=20.19.0" - } - }, "node_modules/moo": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.3.tgz", - "integrity": "sha512-m2fmM2dDm7GZQsY7KK2cme8agi+AAljILjQnof7p1ZMDe6dQ4bdnSMx0cPppudoeNv5hEFQirN6u+O4fDE0IWA==", "dev": true, "license": "BSD-3-Clause", "optional": true }, "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, "license": "MIT", "engines": { @@ -8523,8 +8277,6 @@ }, "node_modules/mrmime": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "devOptional": true, "license": "MIT", "engines": { @@ -8533,57 +8285,17 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, - "node_modules/mysql2": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", - "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", + "node_modules/nan": { + "version": "2.22.2", + "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "aws-ssl-profiles": "^1.1.1", - "denque": "^2.1.0", - "generate-function": "^2.3.1", - "iconv-lite": "^0.7.0", - "long": "^5.2.1", - "lru.min": "^1.0.0", - "named-placeholders": "^1.1.3", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/named-placeholders": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", - "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", - "license": "MIT", - "peer": true, - "dependencies": { - "lru.min": "^1.1.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/nan": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", - "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", - "dev": true, - "license": "MIT", - "optional": true + "optional": true }, "node_modules/nanoid": { "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "devOptional": true, "funding": [ { @@ -8600,9 +8312,9 @@ } }, "node_modules/nanostores": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.1.1.tgz", - "integrity": "sha512-EYJqS25r2iBeTtGQCHidXl1VfZ1jXM7Q04zXJOrMlxVVmD0ptxJaNux92n1mJ7c5lN3zTq12MhH/8x59nP+qmg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.3.0.tgz", + "integrity": "sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA==", "funding": [ { "type": "github", @@ -8616,23 +8328,17 @@ }, "node_modules/napi-build-utils": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", "dev": true, "license": "MIT", "optional": true }, "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, "license": "MIT" }, "node_modules/nearley": { "version": "2.20.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", - "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", "dev": true, "license": "MIT", "optional": true, @@ -8655,16 +8361,12 @@ }, "node_modules/nearley/node_modules/commander": { "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, "license": "MIT", "optional": true }, "node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "dev": true, "license": "MIT", "engines": { @@ -8673,8 +8375,6 @@ }, "node_modules/node-abi": { "version": "3.87.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz", - "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", "dev": true, "license": "MIT", "optional": true, @@ -8685,17 +8385,8 @@ "node": ">=10" } }, - "node_modules/node-fetch-native": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", - "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", - "license": "MIT", - "peer": true - }, "node_modules/node-gyp": { "version": "11.5.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", - "integrity": "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==", "dev": true, "license": "MIT", "optional": true, @@ -8720,8 +8411,6 @@ }, "node_modules/node-gyp/node_modules/isexe": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", - "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "dev": true, "license": "BlueOak-1.0.0", "optional": true, @@ -8731,8 +8420,6 @@ }, "node_modules/node-gyp/node_modules/which": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, "license": "ISC", "optional": true, @@ -8746,10 +8433,61 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/node-stream": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/node-stream/-/node-stream-1.7.0.tgz", + "integrity": "sha512-AB1qHzJWjAuxpDvTr/n1wvKVOg8c9BjAHV21QXq+q9yEUNr7wSqfHmAhAzvpQWSbf8mQQle3fjsnu3R14jrElA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.2", + "readable-stream": "^2.3.3", + "split2": "^2.1.0", + "stream-combiner2": "^1.1.1", + "through2": "^2.0.1" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/node-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/node-stream/node_modules/split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "dev": true, + "license": "ISC", + "dependencies": { + "through2": "^2.0.2" + } + }, + "node_modules/node-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/nopt": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", - "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", "dev": true, "license": "ISC", "optional": true, @@ -8765,8 +8503,6 @@ }, "node_modules/normalize-package-data": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", - "integrity": "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -8778,10 +8514,16 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/normalize-url": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", - "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", "dev": true, "license": "MIT", "optional": true, @@ -8792,35 +8534,8 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nypm": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.5.tgz", - "integrity": "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "citty": "^0.2.0", - "pathe": "^2.0.3", - "tinyexec": "^1.0.2" - }, - "bin": { - "nypm": "dist/cli.mjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/nypm/node_modules/citty": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", - "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", - "license": "MIT", - "peer": true - }, "node_modules/oauth2-mock-server": { "version": "8.2.2", - "resolved": "https://registry.npmjs.org/oauth2-mock-server/-/oauth2-mock-server-8.2.2.tgz", - "integrity": "sha512-ZjMFtomGM4q1DflxEJpq2WVtSLbOjqlJYkkuGWdq9nL3oAbDExamFyhDN/bUqcooCHWeI0n99K/NU+gXEZLNiA==", "dev": true, "license": "MIT", "dependencies": { @@ -8839,8 +8554,6 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "license": "MIT", "engines": { @@ -8849,8 +8562,6 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", "engines": { @@ -8862,8 +8573,6 @@ }, "node_modules/obug": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", "devOptional": true, "funding": [ "https://github.com/sponsors/sxzz", @@ -8871,17 +8580,8 @@ ], "license": "MIT" }, - "node_modules/ohash": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", - "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", - "license": "MIT", - "peer": true - }, "node_modules/on-exit-leak-free": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -8889,8 +8589,6 @@ }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", "dependencies": { @@ -8902,8 +8600,6 @@ }, "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, "license": "ISC", "dependencies": { @@ -8912,8 +8608,6 @@ }, "node_modules/optionator": { "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { @@ -8930,8 +8624,6 @@ }, "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, "license": "MIT", "dependencies": { @@ -8946,8 +8638,6 @@ }, "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, "license": "MIT", "dependencies": { @@ -8962,8 +8652,6 @@ }, "node_modules/p-map": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", - "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", "optional": true, @@ -8976,37 +8664,32 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, - "license": "BlueOak-1.0.0", - "optional": true + "license": "BlueOak-1.0.0" }, "node_modules/package-manager-detector": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", - "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", "dev": true, "license": "MIT" }, "node_modules/packageurl-js": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/packageurl-js/-/packageurl-js-2.0.1.tgz", - "integrity": "sha512-N5ixXjzTy4QDQH0Q9YFjqIWd6zH6936Djpl2m9QNFmDv5Fum8q8BjkpAcHNMzOFE0IwQrFhJWex3AN6kS0OSwg==", "dev": true, "license": "MIT" }, "node_modules/pako": { "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", "dev": true, "license": "MIT" }, + "node_modules/papaparse": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.4.tgz", + "integrity": "sha512-SwzWD9gl/ElwYLCI0nUja1mFJzjq2D8ziShfNBa7zCHzkOozeOGDwHWQ+tvCzEZcewecWZ5U7kUopDnG+DFYEQ==", + "license": "MIT" + }, "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { @@ -9018,8 +8701,6 @@ }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, "license": "MIT", "engines": { @@ -9028,8 +8709,6 @@ }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", "engines": { @@ -9038,8 +8717,6 @@ }, "node_modules/path-expression-matcher": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", - "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", "funding": [ { "type": "github", @@ -9053,8 +8730,7 @@ }, "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, "license": "MIT", "engines": { "node": ">=8" @@ -9062,18 +8738,13 @@ }, "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, "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "license": "BlueOak-1.0.0", - "optional": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -9087,8 +8758,6 @@ }, "node_modules/path-to-regexp": { "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "dev": true, "license": "MIT", "funding": { @@ -9098,21 +8767,96 @@ }, "node_modules/pathe": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/pegjs-backtrace": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/pegjs-backtrace/-/pegjs-backtrace-0.2.1.tgz", + "integrity": "sha512-rnVQiHyTE1wZG14Vl3Xk33ecrF7ZJ7ZW7jSgSlw4LdzBuhbyGVQ+oVApQ6tRi4QsII/xHgByHb6Ax68K6SPLhw==", + "dev": true, + "license": "ISC" + }, + "node_modules/pg": { + "version": "8.21.0", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.13.0", + "pg-pool": "^3.14.0", + "pg-protocol": "^1.14.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.4.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.4.0", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.13.0", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.14.0", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.14.0", "license": "MIT" }, + "node_modules/pg-types": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "devOptional": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "devOptional": true, "license": "MIT", "engines": { @@ -9124,8 +8868,6 @@ }, "node_modules/pino": { "version": "10.3.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", - "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", "license": "MIT", "dependencies": { "@pinojs/redact": "^0.4.0", @@ -9146,8 +8888,6 @@ }, "node_modules/pino-abstract-transport": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", - "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", "license": "MIT", "dependencies": { "split2": "^4.0.0" @@ -9155,8 +8895,6 @@ }, "node_modules/pino-pretty": { "version": "13.1.3", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", - "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", "dev": true, "license": "MIT", "dependencies": { @@ -9180,8 +8918,6 @@ }, "node_modules/pino-pretty/node_modules/strip-json-comments": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", - "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", "dev": true, "license": "MIT", "engines": { @@ -9193,15 +8929,11 @@ }, "node_modules/pino-std-serializers": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", "license": "MIT" }, "node_modules/pixelmatch": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.1.0.tgz", - "integrity": "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "pngjs": "^7.0.0" @@ -9211,21 +8943,143 @@ } }, "node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "version": "2.3.1", + "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", + "confbox": "^0.2.4", + "exsolve": "^1.0.8", "pathe": "^2.0.3" } }, + "node_modules/plantuml-parser": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/plantuml-parser/-/plantuml-parser-0.4.0.tgz", + "integrity": "sha512-IwbkQNgQK/kvXbSYxZWZpcAItk46ECZm6QFA66+smFZqSIjdglXGNTFniO2VLPpgt8uY8EE0uLOsGgvBrerU5Q==", + "dev": true, + "license": " Apache-2.0", + "dependencies": { + "async": "^3.2.0", + "fast-glob": "^3.2.4", + "get-stdin": "^8.0.0", + "json-colorizer": "^2.2.2", + "pegjs-backtrace": "^0.2.0", + "read-vinyl-file-stream": "^2.0.3", + "require-dir": "^1.2.0", + "serialize-error": "^7.0.1", + "yargs": "^16.0.3" + }, + "bin": { + "plantuml-parser": "dist/bin/cli.js" + } + }, + "node_modules/plantuml-parser/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/plantuml-parser/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/plantuml-parser/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/plantuml-parser/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/plantuml-parser/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/plantuml-parser/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/plantuml-parser/node_modules/yargs": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", + "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/plantuml-parser/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/playwright": { "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", - "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "playwright-core": "1.58.2" @@ -9242,9 +9096,7 @@ }, "node_modules/playwright-core": { "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", - "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -9255,9 +9107,7 @@ }, "node_modules/pngjs": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", - "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=14.19.0" @@ -9265,8 +9115,6 @@ }, "node_modules/postcss": { "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "devOptional": true, "funding": [ { @@ -9294,8 +9142,6 @@ }, "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, "license": "MIT", "dependencies": { @@ -9324,8 +9170,6 @@ }, "node_modules/postcss-load-config/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, "license": "ISC", "engines": { @@ -9334,8 +9178,6 @@ }, "node_modules/postcss-safe-parser": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", - "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dev": true, "funding": [ { @@ -9361,8 +9203,6 @@ }, "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": [ { @@ -9388,8 +9228,6 @@ }, "node_modules/postcss-selector-parser": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", - "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -9400,25 +9238,39 @@ "node": ">=4" } }, - "node_modules/postgres": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", - "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", - "license": "Unlicense", - "peer": true, + "node_modules/postgres-array": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" }, - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/porsager" + "engines": { + "node": ">=0.10.0" } }, "node_modules/prebuild-install": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", "dev": true, "license": "MIT", "optional": true, @@ -9445,8 +9297,6 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", "engines": { @@ -9455,8 +9305,6 @@ }, "node_modules/prettier": { "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -9471,8 +9319,6 @@ }, "node_modules/prettier-plugin-svelte": { "version": "3.5.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.5.0.tgz", - "integrity": "sha512-2lLO/7EupnjO/95t+XZesXs8Bf3nYLIDfCo270h5QWbj/vjLqmrQ1LiRk9LPggxSDsnVYfehamZNf+rgQYApZg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -9482,8 +9328,6 @@ }, "node_modules/prettier-plugin-tailwindcss": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.2.tgz", - "integrity": "sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==", "dev": true, "license": "MIT", "engines": { @@ -9561,8 +9405,6 @@ }, "node_modules/pretty-bytes": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.1.0.tgz", - "integrity": "sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==", "license": "MIT", "engines": { "node": ">=20" @@ -9571,55 +9413,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/prisma": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.4.2.tgz", - "integrity": "sha512-2bP8Ruww3Q95Z2eH4Yqh4KAENRsj/SxbdknIVBfd6DmjPwmpsC4OVFMLOeHt6tM3Amh8ebjvstrUz3V/hOe1dA==", - "hasInstallScript": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@prisma/config": "7.4.2", - "@prisma/dev": "0.20.0", - "@prisma/engines": "7.4.2", - "@prisma/studio-core": "0.13.1", - "mysql2": "3.15.3", - "postgres": "3.4.7" - }, - "bin": { - "prisma": "build/index.js" - }, + "node_modules/proc-log": { + "version": "5.0.0", + "dev": true, + "license": "ISC", + "optional": true, "engines": { - "node": "^20.19 || ^22.12 || >=24.0" - }, - "peerDependencies": { - "better-sqlite3": ">=9.0.0", - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "better-sqlite3": { - "optional": true - }, - "typescript": { - "optional": true - } + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/proc-log": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", - "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", + "node_modules/process": { + "version": "0.11.10", "dev": true, - "license": "ISC", - "optional": true, + "license": "MIT", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 0.6.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, "node_modules/process-warning": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", "funding": [ { "type": "github", @@ -9634,8 +9451,6 @@ }, "node_modules/prom-client": { "version": "15.1.3", - "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.3.tgz", - "integrity": "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.4.0", @@ -9647,8 +9462,6 @@ }, "node_modules/promise-retry": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, "license": "MIT", "optional": true, @@ -9662,10 +9475,8 @@ }, "node_modules/proper-lockfile": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", @@ -9674,23 +9485,56 @@ }, "node_modules/proper-lockfile/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC", - "peer": true + "dev": true, + "license": "ISC" + }, + "node_modules/properties-reader": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "mkdirp": "^3.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/properties?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==", "dev": true, "license": "MIT", "optional": true }, + "node_modules/protobufjs": { + "version": "7.6.3", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, "license": "MIT", "dependencies": { @@ -9703,8 +9547,6 @@ }, "node_modules/pump": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "dev": true, "license": "MIT", "dependencies": { @@ -9714,8 +9556,7 @@ }, "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, "license": "MIT", "engines": { "node": ">=6" @@ -9723,8 +9564,7 @@ }, "node_modules/pure-rand": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, "funding": [ { "type": "individual", @@ -9735,12 +9575,11 @@ "url": "https://opencollective.com/fast-check" } ], - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/qs": { "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9755,8 +9594,6 @@ }, "node_modules/quansync": { "version": "0.2.11", - "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", - "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", "dev": true, "funding": [ { @@ -9770,24 +9607,39 @@ ], "license": "MIT" }, + "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" + } + ], + "license": "MIT" + }, "node_modules/quick-format-unescaped": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", "license": "MIT" }, "node_modules/railroad-diagrams": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", - "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", "dev": true, "license": "CC0-1.0", "optional": true }, "node_modules/randexp": { "version": "0.4.6", - "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", - "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", "dev": true, "license": "MIT", "optional": true, @@ -9801,8 +9653,6 @@ }, "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, "license": "MIT", "engines": { @@ -9811,8 +9661,6 @@ }, "node_modules/raw-body": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { @@ -9827,8 +9675,6 @@ }, "node_modules/rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "optional": true, @@ -9844,8 +9690,6 @@ }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, "license": "MIT", "optional": true, @@ -9853,58 +9697,59 @@ "node": ">=0.10.0" } }, - "node_modules/rc9": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", - "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", - "license": "MIT", - "peer": true, + "node_modules/read-vinyl-file-stream": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-vinyl-file-stream/-/read-vinyl-file-stream-2.0.3.tgz", + "integrity": "sha512-ZbtobBf+n/va3eRcIkMDYsp7DCnnjh46YFOOdj42aCiWFirp9T/+YGMCTfVpEFIuiH3c5Kp13jpn3i5DoygxLw==", + "dev": true, + "license": "ISC", "dependencies": { - "defu": "^6.1.4", - "destr": "^2.0.3" + "node-stream": "^1.5.0", + "through2": "^2.0.1" } }, - "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "node_modules/readable-stream": { + "version": "3.6.2", "license": "MIT", - "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, - "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", - "license": "MIT", - "peer": true, + "node_modules/readdir-glob": { + "version": "1.1.3", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.4" + "minimatch": "^5.1.0" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.1.1", + "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.9", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 6" + "node": ">=10" } }, "node_modules/readdirp": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -9916,44 +9761,39 @@ }, "node_modules/real-require": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", "license": "MIT", "engines": { "node": ">= 12.13.0" } }, - "node_modules/regexp-to-ast": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", - "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", - "license": "MIT", - "peer": true - }, "node_modules/regexp-tree": { "version": "0.1.27", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", - "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", "dev": true, "license": "MIT", "bin": { "regexp-tree": "bin/regexp-tree" } }, - "node_modules/remeda": { - "version": "2.33.4", - "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz", - "integrity": "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==", + "node_modules/require-dir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/require-dir/-/require-dir-1.2.0.tgz", + "integrity": "sha512-LY85DTSu+heYgDqq/mK+7zFHWkttVNRXC9NKcKGyuGLdlsfbjEPrIEYdCVrx6hqnJb+xSu3Lzaoo8VnmOhhjNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/remeda" + "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, "license": "MIT", "optional": true, @@ -9963,8 +9803,6 @@ }, "node_modules/resolve": { "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9984,18 +9822,22 @@ }, "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, "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/ret": { "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true, "license": "MIT", "optional": true, @@ -10005,17 +9847,25 @@ }, "node_modules/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10065,8 +9915,6 @@ }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10080,10 +9928,32 @@ "node": ">= 18" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/sade": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, "license": "MIT", "dependencies": { @@ -10095,15 +9965,11 @@ }, "node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "license": "MIT" }, "node_modules/safe-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", - "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", "dev": true, "license": "MIT", "dependencies": { @@ -10112,8 +9978,6 @@ }, "node_modules/safe-stable-stringify": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "license": "MIT", "engines": { "node": ">=10" @@ -10121,21 +9985,11 @@ }, "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, "license": "MIT" }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT", - "peer": true - }, "node_modules/schemes": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/schemes/-/schemes-1.4.0.tgz", - "integrity": "sha512-ImFy9FbCsQlVgnE3TCWmLPCFnVzx0lHL/l+umHplDqAKd0dzFpnS6lFZIpagBlYhKwzVmlV36ec0Y1XTu8JBAQ==", "dev": true, "license": "MIT", "optional": true, @@ -10145,8 +9999,6 @@ }, "node_modules/secure-json-parse": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", - "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", "dev": true, "funding": [ { @@ -10162,8 +10014,6 @@ }, "node_modules/semver": { "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -10175,8 +10025,6 @@ }, "node_modules/send": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10200,16 +10048,37 @@ "url": "https://opencollective.com/express" } }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==", - "peer": true + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/serve-static": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dev": true, "license": "MIT", "dependencies": { @@ -10228,21 +10097,16 @@ }, "node_modules/set-cookie-parser": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.0.1.tgz", - "integrity": "sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==", "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true, "license": "ISC" }, "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, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -10253,8 +10117,7 @@ }, "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, "license": "MIT", "engines": { "node": ">=8" @@ -10262,8 +10125,6 @@ }, "node_modules/side-channel": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", "dependencies": { @@ -10282,8 +10143,6 @@ }, "node_modules/side-channel-list": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, "license": "MIT", "dependencies": { @@ -10299,8 +10158,6 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", "dependencies": { @@ -10318,8 +10175,6 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", "dependencies": { @@ -10338,15 +10193,12 @@ }, "node_modules/siginfo": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "devOptional": true, "license": "ISC" }, "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==", + "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -10357,8 +10209,6 @@ }, "node_modules/simple-concat": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", "dev": true, "funding": [ { @@ -10379,8 +10229,6 @@ }, "node_modules/simple-get": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "dev": true, "funding": [ { @@ -10406,8 +10254,6 @@ }, "node_modules/sirv": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", - "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10421,8 +10267,7 @@ }, "node_modules/smart-buffer": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -10432,8 +10277,6 @@ }, "node_modules/smtp-address-parser": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/smtp-address-parser/-/smtp-address-parser-1.1.0.tgz", - "integrity": "sha512-Gz11jbNU0plrReU9Sj7fmshSBxxJ9ShdD2q4ktHIHo/rpTH6lFyQoYHYKINPJtPe8aHFnsbtW46Ls0tCCBsIZg==", "dev": true, "license": "MIT", "optional": true, @@ -10446,8 +10289,7 @@ }, "node_modules/socks": { "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -10461,8 +10303,6 @@ }, "node_modules/socks-proxy-agent": { "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, "license": "MIT", "optional": true, @@ -10477,37 +10317,38 @@ }, "node_modules/sonic-boom": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", "license": "MIT", "dependencies": { "atomic-sleep": "^1.0.0" } }, + "node_modules/source-map": { + "version": "0.6.1", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "node_modules/source-map-support": { + "version": "0.5.21", + "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { - "memory-pager": "^1.0.2" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, "node_modules/spdx-correct": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -10517,15 +10358,11 @@ }, "node_modules/spdx-exceptions": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10535,15 +10372,16 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.23", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", - "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, + "node_modules/split-ca": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, "node_modules/split2": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "license": "ISC", "engines": { "node": ">= 10.x" @@ -10551,8 +10389,6 @@ }, "node_modules/sqlite-wasm-kysely": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/sqlite-wasm-kysely/-/sqlite-wasm-kysely-0.3.0.tgz", - "integrity": "sha512-TzjBNv7KwRw6E3pdKdlRyZiTmUIE0UttT/Sl56MVwVARl/u5gp978KepazCJZewFUnlWHz9i3NQd4kOtP/Afdg==", "dev": true, "dependencies": { "@sqlite.org/sqlite-wasm": "^3.48.0-build2" @@ -10561,20 +10397,48 @@ "kysely": "*" } }, - "node_modules/sqlstring": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "node_modules/ssh-remote-port-forward": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ssh2": "^0.5.48", + "ssh2": "^1.4.0" + } + }, + "node_modules/ssh-remote-port-forward/node_modules/@types/ssh2": { + "version": "0.5.52", + "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "@types/node": "*", + "@types/ssh2-streams": "*" + } + }, + "node_modules/ssh2": { + "version": "1.17.0", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, "engines": { - "node": ">= 0.6" + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.10", + "nan": "^2.23.0" } }, + "node_modules/ssh2/node_modules/nan": { + "version": "2.27.0", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/ssri": { "version": "12.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", - "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", "dev": true, "license": "ISC", "optional": true, @@ -10587,15 +10451,11 @@ }, "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==", "devOptional": true, "license": "MIT" }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", "engines": { @@ -10604,24 +10464,65 @@ }, "node_modules/std-env": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "devOptional": true, "license": "MIT" }, "node_modules/stream-browserify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", "license": "MIT", "dependencies": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" } }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-combiner2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stream-combiner2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/streamx": { + "version": "2.27.0", + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -10629,8 +10530,6 @@ }, "node_modules/string_decoder/node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -10649,11 +10548,8 @@ }, "node_modules/string-width": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -10669,11 +10565,8 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10685,30 +10578,21 @@ }, "node_modules/string-width-cjs/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==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=8" } }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10718,8 +10602,6 @@ }, "node_modules/stringtemplate4ts": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/stringtemplate4ts/-/stringtemplate4ts-1.0.9.tgz", - "integrity": "sha512-KYZm2bJlSjynG5Y+L46fkaKBQG6mhV6hb2RBA8dpx3/Vj6G4u7gwXNKYvaN9+QD5sj68/1srtSNDvqEso7MwsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10731,18 +10613,13 @@ }, "node_modules/stringtemplate4ts/node_modules/antlr4ng": { "version": "3.0.15", - "resolved": "https://registry.npmjs.org/antlr4ng/-/antlr4ng-3.0.15.tgz", - "integrity": "sha512-VELFqTfcpGI2bj6ScMWuxM3FI6HOsojrgmnw3cCbUtsQ1DNOq32wJsjOt7vLvfIniyyuE1DIYegGcuFmn+jgyw==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/strip-ansi": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^6.2.2" }, @@ -10756,11 +10633,8 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10770,19 +10644,14 @@ }, "node_modules/strip-ansi-cjs/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==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=8" } }, "node_modules/strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { @@ -10791,8 +10660,6 @@ }, "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, "license": "MIT", "engines": { @@ -10804,8 +10671,6 @@ }, "node_modules/strnum": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", - "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", "funding": [ { "type": "github", @@ -10816,8 +10681,6 @@ }, "node_modules/superstruct": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", - "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", "dev": true, "license": "MIT", "optional": true, @@ -10827,8 +10690,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -10840,8 +10701,6 @@ }, "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, "license": "MIT", "engines": { @@ -10853,8 +10712,6 @@ }, "node_modules/svelte": { "version": "5.53.5", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.5.tgz", - "integrity": "sha512-YkqERnF05g8KLdDZwZrF8/i1eSbj6Eoat8Jjr2IfruZz9StLuBqo8sfCSzjosNKd+ZrQ8DkKZDjpO5y3ht1Pow==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10881,8 +10738,6 @@ }, "node_modules/svelte-check": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.4.3.tgz", - "integrity": "sha512-4HtdEv2hOoLCEsSXI+RDELk9okP/4sImWa7X02OjMFFOWeSdFF3NFy3vqpw0z+eH9C88J9vxZfUXz/Uv2A1ANw==", "dev": true, "license": "MIT", "dependencies": { @@ -10905,8 +10760,6 @@ }, "node_modules/svelte-eslint-parser": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.4.1.tgz", - "integrity": "sha512-1eqkfQ93goAhjAXxZiu1SaKI9+0/sxp4JIWQwUpsz7ybehRE5L8dNuz7Iry7K22R47p5/+s9EM+38nHV2OlgXA==", "dev": true, "license": "MIT", "dependencies": { @@ -10935,8 +10788,6 @@ }, "node_modules/svelte/node_modules/is-reference": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10945,8 +10796,6 @@ }, "node_modules/sveltekit-superforms": { "version": "2.30.0", - "resolved": "https://registry.npmjs.org/sveltekit-superforms/-/sveltekit-superforms-2.30.0.tgz", - "integrity": "sha512-EzXD7sHbi7yBU/eNtzVm6P6axcrVM8BArkbiT96Vdx48s5m4KXte/tbbp3UULtEW8Nk9wt2hYkGeq7nDBwVceg==", "dev": true, "funding": [ { @@ -11043,8 +10892,6 @@ }, "node_modules/synckit": { "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11059,8 +10906,6 @@ }, "node_modules/tailwind-csstree": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/tailwind-csstree/-/tailwind-csstree-0.1.4.tgz", - "integrity": "sha512-FzD187HuFIZEyeR7Xy6sJbJll2d4SybS90satC8SKIuaNRC05CxMvdzN7BUsfDQffcnabckRM5OIcfArjsZ0mg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -11073,15 +10918,11 @@ }, "node_modules/tailwindcss": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", - "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", "dev": true, "license": "MIT" }, "node_modules/tapable": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true, "license": "MIT", "engines": { @@ -11094,8 +10935,6 @@ }, "node_modules/tar": { "version": "7.5.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz", - "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==", "dev": true, "license": "BlueOak-1.0.0", "optional": true, @@ -11112,11 +10951,8 @@ }, "node_modules/tar-fs": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -11124,13 +10960,12 @@ "tar-stream": "^2.1.4" } }, - "node_modules/tar-stream": { + "node_modules/tar-fs/node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -11142,10 +10977,20 @@ "node": ">=6" } }, + "node_modules/tar-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/tar/node_modules/chownr": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true, "license": "BlueOak-1.0.0", "optional": true, @@ -11155,17 +11000,62 @@ }, "node_modules/tdigest": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", - "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", "license": "MIT", "dependencies": { "bintrees": "1.0.2" } }, + "node_modules/teex": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/testcontainers": { + "version": "12.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "@types/dockerode": "^4.0.1", + "archiver": "^7.0.1", + "async-lock": "^1.4.1", + "byline": "^5.0.0", + "debug": "^4.4.3", + "docker-compose": "^1.4.2", + "dockerode": "^5.0.0", + "get-port": "^7.2.0", + "proper-lockfile": "^4.1.2", + "properties-reader": "^3.0.1", + "ssh-remote-port-forward": "^1.0.4", + "tar-fs": "^3.1.2", + "tmp": "^0.2.6", + "undici": "^7.25.0" + } + }, + "node_modules/testcontainers/node_modules/tar-fs": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/thread-stream": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", - "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", "license": "MIT", "dependencies": { "real-require": "^0.2.0" @@ -11174,32 +11064,62 @@ "node": ">=20" } }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "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==", "dev": true, "license": "MIT", "optional": true }, "node_modules/tiny-inflate": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "dev": true, "license": "MIT" }, "node_modules/tinybench": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "devOptional": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -11207,8 +11127,6 @@ }, "node_modules/tinyglobby": { "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11224,18 +11142,35 @@ }, "node_modules/tinyrainbow": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", "devOptional": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, + "node_modules/tmp": { + "version": "0.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "license": "MIT", "engines": { @@ -11244,47 +11179,26 @@ }, "node_modules/toposort": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", "dev": true, "license": "MIT", "optional": true }, "node_modules/totalist": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "devOptional": true, "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "license": "MIT", - "peer": true, - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/ts-algebra": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", - "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", "dev": true, "license": "MIT", "optional": true }, "node_modules/ts-api-utils": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { @@ -11296,8 +11210,6 @@ }, "node_modules/ts-deepmerge": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-7.0.3.tgz", - "integrity": "sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==", "dev": true, "license": "ISC", "engines": { @@ -11306,8 +11218,6 @@ }, "node_modules/tsconfig-paths": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, "license": "MIT", "dependencies": { @@ -11321,8 +11231,6 @@ }, "node_modules/tsconfig-paths-webpack-plugin": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz", - "integrity": "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==", "dev": true, "license": "MIT", "dependencies": { @@ -11337,15 +11245,13 @@ }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tsx": { "version": "4.23.13", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.13.tgz", "integrity": "sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "esbuild": "~0.28.0" @@ -11360,438 +11266,1242 @@ "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], "license": "MIT", "optional": true, "os": [ - "darwin" + "aix" ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=18" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "license": "Apache-2.0", + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "license": "MIT", "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, + "os": [ + "android" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "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, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 0.8.0" + "node": ">=18" } }, - "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==", - "dev": true, - "license": "(MIT OR CC0-1.0)", + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "license": "MIT", "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "dev": true, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.6" + "node": ">=18" } }, - "node_modules/typebox": { - "version": "1.0.81", - "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.0.81.tgz", - "integrity": "sha512-bCslZUmZESHhBn4kHDghzH2oo3qu8m2W89xDLxQHv/aPvY4i81Nd1jvijlBp9wSpsVytDSfSoosbiBAjgsNb2Q==", - "dev": true, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "optional": true - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14.17" + "node": ">=18" } }, - "node_modules/typescript-eslint": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz", - "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==", - "dev": true, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.56.1", - "@typescript-eslint/parser": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "node": ">=18" } }, - "node_modules/ufo": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", - "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", - "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=20.18.1" + "node": ">=18" } }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unicode-properties": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", - "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", - "dev": true, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "dev": true, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/unique-filename": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", - "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", - "dev": true, - "license": "ISC", "optional": true, - "dependencies": { - "unique-slug": "^5.0.0" - }, + "os": [ + "linux" + ], "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=18" } }, - "node_modules/unique-slug": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", - "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", - "dev": true, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.28.0", + "devOptional": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, + "node_modules/tsx/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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "dev": true, + "license": "Unlicense" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typebox": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.2.19.tgz", + "integrity": "sha512-9stLVZhos9aUXJzu0Yf717xbcv3vFsE5APzsQ7j/honIUFtern451IdTlqmVzPzuGxHkeWwWc2cerw6m2lqKOQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.56.1", + "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.27.2", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unique-filename": { + "version": "4.0.0", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "unique-slug": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/unique-slug": { + "version": "5.0.0", + "dev": true, "license": "ISC", "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "2.3.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-icons": { + "version": "23.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/utils": "^3.1.0", + "local-pkg": "^1.1.2", + "obug": "^2.1.1", + "unplugin": "^2.3.11" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@svgr/core": ">=7.0.0", + "@svgx/core": "^1.0.1", + "@vue/compiler-sfc": "^3.0.2", + "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@svgr/core": { + "optional": true + }, + "@svgx/core": { + "optional": true + }, + "@vue/compiler-sfc": { + "optional": true + }, + "svelte": { + "optional": true + } + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urlpattern-polyfill": { + "version": "10.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "13.0.2", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/valibot": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validator": { + "version": "13.15.26", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "devOptional": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=18" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.8" + "node": ">=18" } }, - "node_modules/unplugin": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", - "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", - "dev": true, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "acorn": "^8.15.0", - "picomatch": "^4.0.3", - "webpack-virtual-modules": "^0.6.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.12.0" + "node": ">=18" } }, - "node_modules/unplugin-icons": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-23.0.1.tgz", - "integrity": "sha512-rv0XEJepajKzDLvRUWASM8K+8+/CCfZn2jtogXqg6RIp7kpatRc/aFrVJn8ANQA09e++lPEEv9yX8cC9enc+QQ==", - "dev": true, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@iconify/utils": "^3.1.0", - "local-pkg": "^1.1.2", - "obug": "^2.1.1", - "unplugin": "^2.3.11" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@svgr/core": ">=7.0.0", - "@svgx/core": "^1.0.1", - "@vue/compiler-sfc": "^3.0.2", - "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "@svgr/core": { - "optional": true - }, - "@svgx/core": { - "optional": true - }, - "@vue/compiler-sfc": { - "optional": true - }, - "svelte": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "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, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/urlpattern-polyfill": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz", - "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==", - "dev": true, - "license": "MIT" + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/uuid": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.1.tgz", - "integrity": "sha512-9ezox2roIft6ExBVTVqibSd5dc5/47Sw/uY6b4SjQUT2TzQ0tltNquWA46y4xPQmdZYqvnio22SgWd41M86+jw==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" ], "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/valibot": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.2.0.tgz", - "integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==", + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], "license": "MIT", - "peerDependencies": { - "typescript": ">=5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/validator": { - "version": "13.15.26", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", - "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", - "dev": true, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], "license": "MIT", "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">= 0.10" + "node": ">=18" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.8" + "node": ">=18" } }, - "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", - "devOptional": true, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } + "node": ">=18" } }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { "node": ">=18" } }, "node_modules/vite/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "version": "0.27.7", "devOptional": true, "hasInstallScript": true, "license": "MIT", @@ -11802,39 +12512,38 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" } }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -11847,8 +12556,6 @@ }, "node_modules/vitefu": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", - "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", "devOptional": true, "license": "MIT", "workspaces": [ @@ -11867,8 +12574,6 @@ }, "node_modules/vitest": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11945,8 +12650,6 @@ }, "node_modules/vitest-browser-svelte": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/vitest-browser-svelte/-/vitest-browser-svelte-2.0.2.tgz", - "integrity": "sha512-OLJVYoIYflwToFIy3s41pZ9mVp6dwXfYd8IIsWoc57g8DyN3SxsNJ5GB1xWFPxLFlKM+1MPExjPxLaqdELrfRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11960,41 +12663,14 @@ "vitest": "^4.0.0" } }, - "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==", - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=12" - } - }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "dev": true, "license": "MIT" }, - "node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "license": "MIT", - "peer": true, - "dependencies": { - "tr46": "^5.1.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, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -12008,8 +12684,6 @@ }, "node_modules/why-is-node-running": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12025,8 +12699,6 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { @@ -12035,11 +12707,8 @@ }, "node_modules/wrap-ansi": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -12055,11 +12724,8 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -12074,30 +12740,21 @@ }, "node_modules/wrap-ansi-cjs/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==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=8" } }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -12109,11 +12766,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -12123,11 +12777,8 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=12" }, @@ -12137,16 +12788,12 @@ }, "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, "license": "ISC" }, "node_modules/ws": { "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -12166,8 +12813,6 @@ }, "node_modules/xml-naming": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", - "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", "funding": [ { "type": "github", @@ -12181,8 +12826,6 @@ }, "node_modules/xmlbuilder2": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz", - "integrity": "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==", "dev": true, "license": "MIT", "dependencies": { @@ -12195,10 +12838,23 @@ "node": ">=20.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, "license": "BlueOak-1.0.0", "optional": true, @@ -12206,10 +12862,84 @@ "node": ">=18" } }, + "node_modules/yaml": { + "version": "2.9.0", + "devOptional": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "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, "license": "MIT", "engines": { @@ -12221,8 +12951,6 @@ }, "node_modules/yup": { "version": "1.7.1", - "resolved": "https://registry.npmjs.org/yup/-/yup-1.7.1.tgz", - "integrity": "sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==", "dev": true, "license": "MIT", "optional": true, @@ -12233,28 +12961,64 @@ "type-fest": "^2.19.0" } }, - "node_modules/zeptomatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.1.0.tgz", - "integrity": "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==", - "license": "MIT", - "peer": true, - "dependencies": { - "grammex": "^3.1.11", - "graphmatch": "^1.1.0" - } - }, "node_modules/zimmerframe": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", - "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", "devOptional": true, "license": "MIT" }, + "node_modules/zip-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zip-stream/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/zod": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -12262,39 +13026,12 @@ }, "node_modules/zod-v3-to-json-schema": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/zod-v3-to-json-schema/-/zod-v3-to-json-schema-4.0.0.tgz", - "integrity": "sha512-KixLrhX/uPmRFnDgsZrzrk4x5SSJA+PmaE5adbfID9+3KPJcdxqRobaHU397EfWBqfQircrjKqvEqZ/mW5QH6w==", "dev": true, "license": "ISC", "optional": true, "peerDependencies": { "zod": "^3.25 || ^4.0.14" } - }, - "trino-js-client": { - "name": "trino-client", - "version": "0.2.9", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "axios": "1.13.2" - }, - "devDependencies": { - "@eslint/js": "9.25.1", - "@types/eslint__js": "^8.42.3", - "@types/jest": "^30.0.0", - "@types/node": "^24.2.0", - "eslint": "9.39.1", - "eslint-plugin-jest": "^29.0.1", - "jest": "^30.0.5", - "jiti": "^2.4.0", - "prettier": "^3.0.0", - "ts-jest": "^29.2.5", - "ts-node": "^10.9.2", - "typedoc": "^0.28.3", - "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0" - } } } } diff --git a/package.json b/package.json index 2289b662..476a37ad 100644 --- a/package.json +++ b/package.json @@ -12,31 +12,46 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "format": "prettier --write --ignore-path .prettierignore .", - "lint": "prettier --check --ignore-path .prettierignore . && eslint .", - "lint:fix": "prettier --write --ignore-path .prettierignore . && eslint . --fix", + "lint": "prettier --check --ignore-path .prettierignore . && eslint . && npm run check", + "lint:fix": "prettier --write --ignore-path .prettierignore . && eslint . --fix && npm run check", "test:unit": "vitest run", - "test:e2e": "node --env-file=.env.test node_modules/.bin/vite build && playwright test", - "test:e2e:garage": "./e2e/run-garage-tests.sh", + "test:arch": "vitest run --config vitest.arch.config.ts", + "test:arch:report": "ARCH_REPORT=1 vitest run --config vitest.arch.config.ts", + "test:e2e": "node --env-file=.env.test node_modules/.bin/vite build && npx tsx e2e/support/run-e2e.ts", "test:e2e:ui": "playwright test --ui", - "generate:antlr": "cd src/lib/editor/grammar && antlr-ng -v -l -Dlanguage=TypeScript -o ../generated SqlBase.g4 && node patch-generated.mjs" + "generate:antlr": "cd src/lib/editor/grammar && antlr-ng -v -l -Dlanguage=TypeScript -o ../generated SqlBase.g4 && node patch-generated.mjs", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate", + "db:migrate:run": "tsx src/lib/server/migrate.ts", + "db:studio": "drizzle-kit studio" }, "devDependencies": { "@cyclonedx/cyclonedx-npm": "^4.2.1", "@eslint/compat": "^2.0.2", "@eslint/js": "^9.39.2", "@faker-js/faker": "^10.4.0", + "@iconify-json/lsicon": "^1.2.5", + "@iconify-json/material-icon-theme": "^1.2.67", "@iconify-json/material-symbols": "^1.2.74", + "@iconify-json/vscode-icons": "^1.2.55", "@inlang/paraglide-js": "^2.12.0", "@playwright/test": "^1.58.2", "@sveltejs/adapter-node": "^5.5.3", "@sveltejs/kit": "^2.53.0", "@sveltejs/vite-plugin-svelte": "^6.2.4", "@tailwindcss/vite": "^4.2.1", + "@testcontainers/postgresql": "^12.0.1", + "@types/adm-zip": "^0.5.8", "@types/node": "^24", + "@types/papaparse": "^5.5.2", + "@types/pg": "^8.20.0", + "@types/tar-stream": "^3.1.4", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", "antlr-ng": "^1.0.10", + "archunit": "^2.3.3", "daisyui": "^5.5.19", + "drizzle-kit": "^0.31.10", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", "eslint-plugin-better-tailwindcss": "^4.3.0", @@ -52,6 +67,7 @@ "svelte-check": "^4.4.3", "sveltekit-superforms": "^2.30.0", "tailwindcss": "^4.2.1", + "testcontainers": "^12.0.1", "tsx": "^4.23.13", "typescript": "^5.9.3", "typescript-eslint": "^8.56.1", @@ -64,17 +80,28 @@ "dependencies": { "@aws-sdk/client-s3": "^3.1041.0", "@aws-sdk/lib-storage": "^3.1045.0", + "@better-auth/drizzle-adapter": "^1.6.20", "@internationalized/date": "^3.11.0", "@smithy/node-http-handler": "4.9.1", + "adm-zip": "^0.5.17", "antlr4-c3": "^3.4.4", "antlr4ng": "^3.0.16", - "better-auth": "^1.5.4", + "better-auth": "^1.6.20", + "drizzle-orm": "^0.45.2", "hyparquet": "^1.25.8", "hyparquet-compressors": "^1.1.1", "monaco-editor": "^0.55.1", + "papaparse": "^5.5.3", + "pg": "^8.21.0", "pino": "^10.3.1", "pretty-bytes": "^7.1.0", "prom-client": "^15.1.3", + "tar-stream": "^3.2.0", "undici": "^7.24.4" + }, + "overrides": { + "sveltekit-superforms": { + "typebox": "1.2.19" + } } } diff --git a/playwright.config.ts b/playwright.config.ts index 568b4946..f47bf143 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -5,10 +5,12 @@ const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:4173'; const chromiumExecutablePath = process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH; export default defineConfig({ + workers: process.env.CI ? 1 : 1, testDir: path.join(import.meta.dirname, 'e2e'), outputDir: path.join(import.meta.dirname, 'e2e/test-results'), globalSetup: path.join(import.meta.dirname, 'e2e/support/global-setup.ts'), - timeout: 60_000, + timeout: 20_000, + globalTimeout: 40 * 60_000, retries: 2, expect: { timeout: 10_000 @@ -16,32 +18,41 @@ export default defineConfig({ use: { baseURL, trace: 'retain-on-failure', - video: 'retain-on-failure' + video: 'retain-on-failure', + screenshot: 'only-on-failure' }, webServer: [ { command: 'npx tsx e2e/support/start-mock-oidc.ts', url: 'http://localhost:9090/.well-known/openid-configuration', - reuseExistingServer: true + reuseExistingServer: false }, { command: 'npx tsx e2e/support/start-mock-trino.ts', url: 'http://localhost:8080', - reuseExistingServer: true + reuseExistingServer: false }, { - command: 'PORT=4173 node --env-file=.env.test build', + command: 'node --env-file=.env.test build/index.js', url: baseURL, - reuseExistingServer: true + reuseExistingServer: false } ], projects: [ + // Runs database migrations against the PostgreSQL container started by globalSetup. + // All browser projects depend on this so tests never run on an unmigrated DB. + // Container teardown is handled by the function returned from globalSetup. + { + name: 'setup-db', + testMatch: /db-migrations\.setup\.ts/ + }, // Each browser project gets its own auth setup so that parallel workers // log in as different users. This prevents cross-worker races on shared // server-side state (e.g. the in-memory Trino connection store). { name: 'setup-chromium', testMatch: /auth\.setup\.ts/, + dependencies: ['setup-db'], use: { browserName: 'chromium', viewport: { width: 1280, height: 720 } @@ -50,23 +61,12 @@ export default defineConfig({ { name: 'setup-firefox', testMatch: /auth\.setup\.ts/, + dependencies: ['setup-db'], use: { browserName: 'firefox', viewport: { width: 1280, height: 720 } } }, - ...(!process.env.CI - ? [ - { - name: 'setup-mobile', - testMatch: /auth\.setup\.ts/, - use: { - browserName: 'chromium' as const, - viewport: { width: 393, height: 851 } - } - } - ] - : []), { name: 'firefox', use: { @@ -85,24 +85,6 @@ export default defineConfig({ ...(chromiumExecutablePath && { launchOptions: { executablePath: chromiumExecutablePath } }) }, dependencies: ['setup-chromium'] - }, - ...(!process.env.CI - ? [ - { - name: 'mobile', - use: { - browserName: 'chromium' as const, - viewport: { width: 393, height: 851 }, - isMobile: true, - hasTouch: true, - storageState: 'e2e/.auth/user-setup-mobile.json', - ...(chromiumExecutablePath && { - launchOptions: { executablePath: chromiumExecutablePath } - }) - }, - dependencies: ['setup-mobile'] - } - ] - : []) + } ] }); diff --git a/src/app.css b/src/app.css index 30b34902..cda5b74d 100644 --- a/src/app.css +++ b/src/app.css @@ -24,6 +24,14 @@ progress.progress::-moz-progress-bar { transition: none; } +/* Smooth transition for operation progress bars where discrete chunk updates benefit from animation */ +progress.progress.progress-smooth::-webkit-progress-value { + transition: width 0.4s ease; +} +progress.progress.progress-smooth::-moz-progress-bar { + transition: width 0.4s ease; +} + /* * Visible scrollbars for preview panels. Uses DaisyUI semantic color variables * so the thumb adapts to both light and dark themes automatically. @@ -52,3 +60,12 @@ progress.progress::-moz-progress-bar { .preview-scroll::-webkit-scrollbar-thumb:hover { background-color: color-mix(in oklch, currentColor 50%, transparent); } + +@keyframes nav-progress-slide { + 0% { + transform: translateX(-110%); + } + 100% { + transform: translateX(350%); + } +} diff --git a/src/app.d.ts b/src/app.d.ts index f31b166a..0d6473c6 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -16,8 +16,9 @@ declare global { logger: import('pino').Logger; requestId: string; /** - * Parsed S3 connection config extracted from the `x-storage-connection` - * request header by the `handleStorageConnection` middleware. + * Parsed S3 connection config extracted from the `x-storage-connection-id` + * request header by the `handleStorageConnection` middleware. The connection is + * looked up from the database and decrypted using the application key. * Always non-null for requests to `/(app)/api/storage/*` routes * (the middleware throws 401 before the handler runs if the header is absent). * Null for all other routes. diff --git a/src/app.html b/src/app.html index 023799df..ea0df32a 100644 --- a/src/app.html +++ b/src/app.html @@ -6,10 +6,18 @@ %sveltekit.head% diff --git a/src/architecture/circular-dependencies.spec.ts b/src/architecture/circular-dependencies.spec.ts new file mode 100644 index 00000000..44ddad1e --- /dev/null +++ b/src/architecture/circular-dependencies.spec.ts @@ -0,0 +1,50 @@ +/** + * No Circular Dependencies + * + * Import cycles cause unpredictable initialisation order, make tree-shaking + * less effective and are a strong signal of coupled, hard-to-refactor code. + * + * Known violations (see TECH_DEBT.md — "Circular imports in Trino layer"): + * • src/lib/server/trino/client.ts ↔ src/lib/server/trino/user-clients.ts + * • src/lib/server/trino/queries.ts ↔ src/lib/server/trino/result-collector.ts + * + * These are excluded from the cycle check below until the Trino layer is + * refactored to extract shared types into a separate file. + */ + +import { projectFiles } from 'archunit'; +import { describe, expect, it } from 'vitest'; +import { defaultOptions } from './helpers'; + +describe('No Circular Dependencies', () => { + it('src/lib must be free of import cycles (excluding generated and known-cyclic Trino files)', async () => { + const rule = projectFiles() + .inPath('src/lib/**/*.ts', { + except: { + inPath: 'src/lib/editor/generated/**' + } + }) + .inPath('src/lib/**/*.ts', { + except: { + inPath: 'src/lib/server/trino/**' + } + }) + .should() + .haveNoCycles(); + + await expect(rule).toPassAsync(defaultOptions); + }); + + it('SvelteKit routes must be free of import cycles', async () => { + const rule = projectFiles().inPath('src/routes/**/*.ts').should().haveNoCycles(); + + await expect(rule).toPassAsync(defaultOptions); + }); + + it('KNOWN VIOLATION — Trino layer has circular imports (see TECH_DEBT.md)', async () => { + const rule = projectFiles().inPath('src/lib/server/trino/**/*.ts').should().haveNoCycles(); + + const violations = await rule.check(); + expect(violations.length).toBeGreaterThan(0); + }); +}); diff --git a/src/architecture/code-size-limits.spec.ts b/src/architecture/code-size-limits.spec.ts new file mode 100644 index 00000000..c0a1111a --- /dev/null +++ b/src/architecture/code-size-limits.spec.ts @@ -0,0 +1,66 @@ +/** + * Code Size Limits + * + * Very large files are a leading indicator of insufficient separation of + * concerns and increase cognitive load for both humans and AI coding assistants. + * + * Thresholds are set above current maximums to pass today but act as guardrails + * against further growth. Tighten them as large files are split during normal + * refactoring cycles. + * + * Current maximums (non-generated): + * src/lib/storage/state.svelte.ts ~2 331 LOC ← split candidate + * src/lib/server/storage/archive.ts ~919 LOC + * src/lib/components/storage/modals/PreviewModal.svelte ~1 065 LOC + */ + +import { readFileSync } from 'node:fs'; +import { describe, expect, it } from 'vitest'; +import { findFiles } from './helpers'; + +describe('Code Size Limits', () => { + it('TypeScript source files must not exceed 2 400 lines of code', () => { + const MAX_LOC = 2400; + const violations: string[] = []; + + const files = findFiles('src', /\.ts$/, [/editor\/generated/, /paraglide/]); + for (const file of files) { + const lines = readFileSync(file, 'utf-8').split('\n').length; + if (lines >= MAX_LOC) { + violations.push(`${file} (${lines} lines, max ${MAX_LOC})`); + } + } + + expect(violations).toStrictEqual([]); + }); + + it('Svelte component files must not exceed 1 100 lines', () => { + const MAX_LOC = 1100; + const violations: string[] = []; + + const files = findFiles('src', /\.svelte$/); + for (const file of files) { + const lines = readFileSync(file, 'utf-8').split('\n').length; + if (lines >= MAX_LOC) { + violations.push(`${file} (${lines} lines, max ${MAX_LOC})`); + } + } + + expect(violations).toStrictEqual([]); + }); + + it('individual test files must not exceed 1 000 lines of code', () => { + const MAX_LOC = 1000; + const violations: string[] = []; + + const files = findFiles('src', /\.(test|spec)\.ts$/, [/editor\/generated/]); + for (const file of files) { + const lines = readFileSync(file, 'utf-8').split('\n').length; + if (lines >= MAX_LOC) { + violations.push(`${file} (${lines} lines, max ${MAX_LOC})`); + } + } + + expect(violations).toStrictEqual([]); + }); +}); diff --git a/src/architecture/helpers.ts b/src/architecture/helpers.ts new file mode 100644 index 00000000..6dba29e7 --- /dev/null +++ b/src/architecture/helpers.ts @@ -0,0 +1,61 @@ +/** + * Shared helpers for architecture fitness tests. + * + * ArchUnitTS only scans TypeScript (.ts) source files. Svelte (.svelte) and + * JSON files are invisible to its file graph. Rules that need to inspect + * .svelte file content therefore use plain Node.js fs helpers instead. + */ + +import { readdirSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; + +/** Standard options: suppress verbose logs, fail on empty patterns. */ +export const defaultOptions = { + logging: { enabled: false, level: 'warn' as const } +}; + +/** + * Recursively collect all files under `dir` whose names match `filenamePattern`. + * Hidden directories (starting with `.`) are skipped automatically. + */ +export function findFiles( + dir: string, + filenamePattern: RegExp, + excludeDirs: RegExp[] = [] +): string[] { + const results: string[] = []; + let entries; + try { + entries = readdirSync(dir, { withFileTypes: true }); + } catch { + return results; + } + for (const entry of entries) { + const fullPath = join(dir, entry.name); + if (entry.isDirectory()) { + if (entry.name.startsWith('.')) continue; + if (excludeDirs.some((p) => p.test(fullPath))) continue; + results.push(...findFiles(fullPath, filenamePattern, excludeDirs)); + } else if (entry.isFile() && filenamePattern.test(entry.name)) { + results.push(fullPath); + } + } + return results; +} + +/** + * Check every file returned by `findFiles` against `predicate`. + * Returns a list of `{ file, reason }` violation objects. + */ +export function checkFiles( + files: string[], + predicate: (content: string) => boolean, + reason: string +): Array<{ file: string; reason: string }> { + return files + .filter((file) => { + const content = readFileSync(file, 'utf-8'); + return !predicate(content); + }) + .map((file) => ({ file, reason })); +} diff --git a/src/architecture/i18n-compliance.spec.ts b/src/architecture/i18n-compliance.spec.ts new file mode 100644 index 00000000..8a1b7de3 --- /dev/null +++ b/src/architecture/i18n-compliance.spec.ts @@ -0,0 +1,61 @@ +/** + * i18n Compliance + * + * All user-visible strings must be served through Paraglide-JS message + * functions so that the application renders correctly in both English (en) + * and German (de). + * + * Rules: + * a) Both locale files (messages/en.json, messages/de.json) must have the + * same top-level keys — missing translations break the German locale. + * b) Svelte components must not use hardcoded English strings in static + * aria-label="..." attributes (dynamic bindings are allowed). + */ + +import { readFileSync } from 'node:fs'; +import { describe, expect, it } from 'vitest'; +import { findFiles } from './helpers'; + +describe('i18n Compliance', () => { + it('messages/en.json and messages/de.json must have the same top-level keys', () => { + const en: Record = JSON.parse(readFileSync('messages/en.json', 'utf-8')); + const de: Record = JSON.parse(readFileSync('messages/de.json', 'utf-8')); + + const enKeys = Object.keys(en).sort(); + const deKeys = Object.keys(de).sort(); + + const missingInDe = enKeys.filter((k) => !deKeys.includes(k)); + const missingInEn = deKeys.filter((k) => !enKeys.includes(k)); + + expect(missingInDe).toStrictEqual([]); + expect(missingInEn).toStrictEqual([]); + }); + + it('Svelte components must not use static English strings in aria-label attributes', () => { + const KNOWN_VIOLATIONS = [ + 'ToastHost.svelte', + 'TextEditor.svelte', + 'ContextMenu.svelte', + 'FileRow.svelte', + 'FolderRow.svelte', + 'ObjectTable.svelte', + 'StorageBreadcrumb.svelte', + 'CsvPreview.svelte', + 'ParquetPreview.svelte', + 'TextPreview.svelte' + ]; + + const STATIC_ARIA_RE = /aria-label="[A-Za-z][^"]{2,}"/; + + const files = findFiles('src', /\.svelte$/); + const allViolations = files.filter((file) => { + const content = readFileSync(file, 'utf-8'); + return STATIC_ARIA_RE.test(content); + }); + + const newViolations = allViolations.filter( + (f) => !KNOWN_VIOLATIONS.some((kv) => f.endsWith(kv)) + ); + expect(newViolations).toStrictEqual([]); + }); +}); diff --git a/src/architecture/naming-conventions.spec.ts b/src/architecture/naming-conventions.spec.ts new file mode 100644 index 00000000..b83b8123 --- /dev/null +++ b/src/architecture/naming-conventions.spec.ts @@ -0,0 +1,46 @@ +/** + * Naming Conventions + * + * Consistent naming makes the codebase predictable and allows tooling + * (SvelteKit, Vitest, ESLint) to apply the correct transforms automatically. + * + * Rules derived from AGENTS.md: + * • Svelte 5 rune-based stores use the `.svelte.ts` extension so that + * Svelte's compiler processes the rune syntax ($state, $derived, etc.) + * • Svelte components in src/lib/components/ are PascalCase (checked via fs + * because archunit does not scan .svelte files) + */ + +import { describe, expect, it } from 'vitest'; +import { findFiles } from './helpers'; + +describe('Naming Conventions', () => { + it('files in src/lib/stores/ must use the .svelte.ts extension', () => { + // Svelte 5 rune-based reactive state ($state, $derived) only compiles + // correctly when the file extension is .svelte.ts. + // Spec files (*.spec.ts) are excluded from this check. + const violations = findFiles('src/lib/stores', /\.ts$/, [/__tests__/]).filter((f) => { + const name = f.split('/').at(-1) ?? ''; + return !name.endsWith('.svelte.ts') && !name.endsWith('.spec.ts'); + }); + + expect(violations).toStrictEqual([]); + }); + + it('Svelte components in src/lib/components/ must be PascalCase', () => { + const PASCAL_CASE = /^[A-Z][a-zA-Z0-9]*\.svelte$/; + const svelteFiles = findFiles('src/lib/components', /\.svelte$/, [/__tests__/, /\.spec\./]); + + const violations = svelteFiles.filter((f) => { + const name = f.split('/').at(-1) ?? ''; + return !PASCAL_CASE.test(name); + }); + + expect(violations).toStrictEqual([]); + }); + + it('src/lib/server/ files must not use .svelte.ts extension', () => { + const violations = findFiles('src/lib/server', /\.svelte\.ts$/); + expect(violations).toStrictEqual([]); + }); +}); diff --git a/src/architecture/report-generation.spec.ts b/src/architecture/report-generation.spec.ts new file mode 100644 index 00000000..66ced76e --- /dev/null +++ b/src/architecture/report-generation.spec.ts @@ -0,0 +1,50 @@ +/** + * Architecture Reports + * + * Run `npm run test:arch:report` to generate HTML dashboards in /reports/. + * These can be committed as CI artefacts for architecture review. + */ + +import { describe, expect, it } from 'vitest'; + +describe('Architecture Reports (run manually with test:arch:report)', () => { + it('should export dependency graph for src/lib', async () => { + if (!process.env.ARCH_REPORT) { + expect(true).toBe(true); + return; + } + + const { projectGraph } = await import('archunit'); + await projectGraph() + .titled('Stackable Cockpit — src/lib Dependency Graph') + .focusOn('src/lib/**', 2) + .exportAsHTML('reports/lib-dependency-graph.html'); + + await projectGraph() + .titled('Stackable Cockpit — Full Source Graph') + .collapseToFolderDepth(3) + .exportAsMermaid('reports/source-graph.mmd'); + + expect(true).toBe(true); + }); + + it('should export code metrics report', async () => { + if (!process.env.ARCH_REPORT) { + expect(true).toBe(true); + return; + } + + const { metrics } = await import('archunit'); + await metrics() + .inPath('src/**/*.ts', { + except: { inPath: 'src/lib/editor/generated/**' } + }) + .count() + .exportAsHTML('reports/count-metrics.html', { + title: 'Stackable Cockpit — Count Metrics', + includeTimestamp: true + }); + + expect(true).toBe(true); + }); +}); diff --git a/src/architecture/server-client-boundary.spec.ts b/src/architecture/server-client-boundary.spec.ts new file mode 100644 index 00000000..bd116ccf --- /dev/null +++ b/src/architecture/server-client-boundary.spec.ts @@ -0,0 +1,93 @@ +/** + * Server / Client Boundary + * + * The server layer (src/lib/server/**) contains database access, auth tokens, + * storage credentials, pino loggers and Prometheus metrics that must NEVER be + * bundled into the client. Any import of server code from client-side files is + * a security and build risk. + * + * Known legitimate cross-boundary pattern: + * • Svelte component files (.svelte) may use `import type { … }` from server + * type files. TypeScript erases these at compile time so there is no runtime + * dependency. ArchUnitTS cannot distinguish type-only imports in .ts files, + * but since it does not scan .svelte files anyway, this is not an issue here. + * Long-term fix: move shared types to src/lib/types/ — see TECH_DEBT.md. + */ + +import { projectFiles } from 'archunit'; +import { describe, expect, it } from 'vitest'; +import { defaultOptions } from './helpers'; + +describe('Server / Client Boundary', () => { + it('client-only utilities (src/lib/client) must not import server code', async () => { + const rule = projectFiles() + .inPath('src/lib/client/**/*.ts') + .shouldNot() + .dependOnFiles() + .inPath('src/lib/server/**'); + + await expect(rule).toPassAsync(defaultOptions); + }); + + it('Svelte reactive stores (src/lib/stores) must not import server code', async () => { + const rule = projectFiles() + .inPath('src/lib/stores/**/*.ts') + .shouldNot() + .dependOnFiles() + .inPath('src/lib/server/**'); + + await expect(rule).toPassAsync(defaultOptions); + }); + + it('shared storage utilities (src/lib/storage) must not import server code', async () => { + const rule = projectFiles() + .inPath('src/lib/storage/**/*.ts') + .shouldNot() + .dependOnFiles() + .inPath('src/lib/server/**'); + + await expect(rule).toPassAsync(defaultOptions); + }); + + it('Monaco/ANTLR editor code must not import server code', async () => { + const rule = projectFiles() + .inPath('src/lib/editor/**/*.ts', { + except: { inPath: 'src/lib/editor/generated/**' } + }) + .shouldNot() + .dependOnFiles() + .inPath('src/lib/server/**'); + + await expect(rule).toPassAsync(defaultOptions); + }); + + it('shared type definitions (src/lib/types) must not import server code', async () => { + const rule = projectFiles() + .inPath('src/lib/types/**/*.ts') + .shouldNot() + .dependOnFiles() + .inPath('src/lib/server/**'); + + await expect(rule).toPassAsync(defaultOptions); + }); + + it('server code must not import client-only utilities', async () => { + const rule = projectFiles() + .inPath('src/lib/server/**/*.ts') + .shouldNot() + .dependOnFiles() + .inPath('src/lib/client/**'); + + await expect(rule).toPassAsync(defaultOptions); + }); + + it('server code must not import Svelte reactive stores', async () => { + const rule = projectFiles() + .inPath('src/lib/server/**/*.ts') + .shouldNot() + .dependOnFiles() + .inPath('src/lib/stores/**'); + + await expect(rule).toPassAsync(defaultOptions); + }); +}); diff --git a/src/architecture/server-logging.spec.ts b/src/architecture/server-logging.spec.ts new file mode 100644 index 00000000..186f27a7 --- /dev/null +++ b/src/architecture/server-logging.spec.ts @@ -0,0 +1,68 @@ +/** + * Server-Side Logging Standards + * + * All server-side code must use pino (via $lib/server/logging) instead of + * console.* so that logs are structured JSON, include request correlation IDs, + * and can be filtered/routed by log level in production. + * + * Exceptions: + * • src/lib/server/migrate.ts — standalone CLI migration runner that executes + * before the application server and pino logger are initialised. + */ + +import { readFileSync } from 'node:fs'; +import { describe, expect, it } from 'vitest'; +import { findFiles } from './helpers'; + +describe('Server-Side Logging Standards', () => { + it('server lib files must not call console.log/warn/error/info/debug', () => { + const CONSOLE_CALL_RE = /\bconsole\.(log|warn|error|info|debug)\s*\(/; + const COMMENT_LINE_RE = /^\s*(\/\/|\/\*|\*)/; + + const files = findFiles('src/lib/server', /\.ts$/).filter( + (f) => !f.endsWith('migrate.ts') && !f.includes('.test.') && !f.includes('.spec.') + ); + + const violations: string[] = []; + + for (const file of files) { + const lines = readFileSync(file, 'utf-8').split('\n'); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (COMMENT_LINE_RE.test(line)) continue; + if (!CONSOLE_CALL_RE.test(line)) continue; + const matchIdx = line.search(CONSOLE_CALL_RE); + const before = line.substring(0, matchIdx); + const openDoubleQuotes = (before.match(/(? { + const CONSOLE_CALL_RE = /\bconsole\.(log|warn|error|info|debug)\s*\(/; + const COMMENT_OR_STRING_RE = /^\s*(\/\/|\/\*|\*)/; + + const files = findFiles('src/routes', /\.server\.ts$/); + const violations: string[] = []; + + for (const file of files) { + const lines = readFileSync(file, 'utf-8').split('\n'); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (COMMENT_OR_STRING_RE.test(line)) continue; + if (CONSOLE_CALL_RE.test(line) && !line.includes('//')) { + violations.push(`${file}:${i + 1}: ${line.trim()}`); + } + } + } + + expect(violations).toStrictEqual([]); + }); +}); diff --git a/src/architecture/ui-pattern-enforcement.spec.ts b/src/architecture/ui-pattern-enforcement.spec.ts new file mode 100644 index 00000000..7b571855 --- /dev/null +++ b/src/architecture/ui-pattern-enforcement.spec.ts @@ -0,0 +1,100 @@ +/** + * UI Pattern Enforcement + * + * These rules enforce the coding standards from AGENTS.md that apply to Svelte + * component files. They inspect raw file content via Node.js fs since ArchUnitTS + * does not scan .svelte files. + * + * Rules: + * a) No hardcoded Tailwind colour utilities — use DaisyUI semantic classes + * so that light/dark theme switching works automatically. + * b) No raw elements outside Modal.svelte — always use the shared + * component which handles focus trapping, Escape, and backdrop. + * c) No native / — always + * use the shared component. + * d) No without an alt attribute — BITV 2.0 / WCAG 2.1 AA compliance. + * e) No
/ — use - - - {#if showLast} +
+ +
+
+ +
+
+
+ {#if showLast} +
+ +
{/if} {/if} @@ -162,43 +166,47 @@ {infoLabel} {/if}
diff --git a/src/lib/components/TabBar.svelte b/src/lib/components/TabBar.svelte index 53586b2c..01187a23 100644 --- a/src/lib/components/TabBar.svelte +++ b/src/lib/components/TabBar.svelte @@ -1,5 +1,6 @@ - -
+
{#each toasts as toast (toast.id)} {@const ToastIcon = iconMap[toast.type]} {/each}
diff --git a/src/lib/components/ToastHost.svelte.spec.ts b/src/lib/components/ToastHost.svelte.spec.ts new file mode 100644 index 00000000..114dc574 --- /dev/null +++ b/src/lib/components/ToastHost.svelte.spec.ts @@ -0,0 +1,50 @@ +import { page } from 'vitest/browser'; +import { describe, expect, it, beforeEach } from 'vitest'; +import { render } from 'vitest-browser-svelte'; +import ToastHost from './ToastHost.svelte'; +import { toasts, addToast } from '$lib/stores/toast.svelte.js'; + +beforeEach(() => { + toasts.length = 0; +}); + +describe('ToastHost', () => { + it('renders nothing when there are no toasts', () => { + render(ToastHost); + expect(page.getByRole('alert').query()).toBeNull(); + }); + + it('renders a toast added before render', () => { + addToast('info', 'Pre-existing toast'); + render(ToastHost); + expect(page.getByText('Pre-existing toast').query()).not.toBeNull(); + }); + + it('labels the dismiss button', () => { + addToast('info', 'Hello'); + render(ToastHost); + const dismissBtn = page.getByRole('button', { name: 'Dismiss' }); + expect(dismissBtn.query()).not.toBeNull(); + }); + + it('renders multiple pre-existing toasts', () => { + addToast('info', 'First'); + addToast('success', 'Second'); + render(ToastHost); + const alerts = document.querySelectorAll('[role="alert"]'); + expect(alerts.length).toBe(2); + }); + + it('renders action buttons when toast has actions', () => { + addToast('warning', 'With action', 5000, [{ label: 'Undo', onClick: () => {} }]); + render(ToastHost); + const undoBtn = page.getByText('Undo'); + expect(undoBtn.query()).not.toBeNull(); + }); + + it('has aria-live="polite" for screen reader announcements', () => { + render(ToastHost); + const container = document.querySelector('[aria-live="polite"]'); + expect(container).not.toBeNull(); + }); +}); diff --git a/src/lib/components/Tooltip.svelte b/src/lib/components/Tooltip.svelte new file mode 100644 index 00000000..e61d773e --- /dev/null +++ b/src/lib/components/Tooltip.svelte @@ -0,0 +1,47 @@ + + +{#if text} +
+
+ + {text} +
+
+{/if} diff --git a/src/lib/components/Tooltip.svelte.spec.ts b/src/lib/components/Tooltip.svelte.spec.ts new file mode 100644 index 00000000..0ec9535a --- /dev/null +++ b/src/lib/components/Tooltip.svelte.spec.ts @@ -0,0 +1,64 @@ +import { page } from 'vitest/browser'; +import { describe, expect, it } from 'vitest'; +import { render } from 'vitest-browser-svelte'; +import Tooltip from './Tooltip.svelte'; + +describe('Tooltip', () => { + it('renders tooltip text', async () => { + render(Tooltip, { text: 'Helpful info', x: 100, y: 200 }); + const tooltip = page.getByText('Helpful info'); + await expect.element(tooltip).toBeInTheDocument(); + }); + + it('has role="tooltip"', async () => { + render(Tooltip, { text: 'Info', x: 0, y: 0 }); + const tooltip = page.getByRole('tooltip'); + await expect.element(tooltip).toBeInTheDocument(); + }); + + it('does not render when text is null', () => { + render(Tooltip, { text: null, x: 100, y: 200 }); + expect(page.getByRole('tooltip').query()).toBeNull(); + }); + + it('does not render when text is empty string', () => { + render(Tooltip, { text: '', x: 100, y: 200 }); + expect(page.getByRole('tooltip').query()).toBeNull(); + }); + + it('positions based on right orientation (default)', async () => { + render(Tooltip, { text: 'Right', x: 50, y: 100 }); + const tooltip = page.getByRole('tooltip'); + const el = await tooltip.element(); + const style = el.getAttribute('style'); + expect(style).toContain('left: 56px'); + expect(style).toContain('top: 100px'); + }); + + it('positions based on left orientation', async () => { + render(Tooltip, { text: 'Left', x: 50, y: 100, orientation: 'left' }); + const tooltip = page.getByRole('tooltip'); + const el = await tooltip.element(); + const style = el.getAttribute('style'); + expect(style).toContain('left: 44px'); + expect(style).toContain('top: 100px'); + }); + + it('positions based on up orientation', async () => { + render(Tooltip, { text: 'Up', x: 50, y: 100, orientation: 'up' }); + const tooltip = page.getByRole('tooltip'); + const el = await tooltip.element(); + const style = el.getAttribute('style'); + expect(style).toContain('left: 50px'); + expect(style).toContain('top: 94px'); + }); + + it('positions based on down orientation', async () => { + render(Tooltip, { text: 'Down', x: 50, y: 100, orientation: 'down' }); + const tooltip = page.getByRole('tooltip'); + const el = await tooltip.element(); + const style = el.getAttribute('style'); + expect(style).toContain('left: 50px'); + expect(style).toContain('top: 106px'); + }); +}); diff --git a/src/lib/components/TooltipTrigger.svelte b/src/lib/components/TooltipTrigger.svelte new file mode 100644 index 00000000..d1bf1a51 --- /dev/null +++ b/src/lib/components/TooltipTrigger.svelte @@ -0,0 +1,118 @@ + + + + {@render children()} + diff --git a/src/lib/components/TooltipTrigger.svelte.spec.ts b/src/lib/components/TooltipTrigger.svelte.spec.ts new file mode 100644 index 00000000..62025d03 --- /dev/null +++ b/src/lib/components/TooltipTrigger.svelte.spec.ts @@ -0,0 +1,74 @@ +import { page, userEvent } from 'vitest/browser'; +import { describe, expect, it } from 'vitest'; +import { render } from 'vitest-browser-svelte'; +import TooltipTriggerWrapper from './__tests__/TooltipTriggerWrapper.svelte'; +import TooltipTriggerDialogWrapper from './__tests__/TooltipTriggerDialogWrapper.svelte'; + +describe('TooltipTrigger', () => { + it('renders the trigger content without a tooltip', async () => { + render(TooltipTriggerWrapper, { text: 'Delete' }); + await expect.element(page.getByRole('button', { name: 'Trigger' })).toBeInTheDocument(); + expect(page.getByRole('tooltip').query()).toBeNull(); + }); + + it('shows the tooltip when the trigger is hovered', async () => { + render(TooltipTriggerWrapper, { text: 'Delete' }); + await page.getByRole('button', { name: 'Trigger' }).hover(); + const tooltip = page.getByRole('tooltip'); + await expect.element(tooltip).toBeInTheDocument(); + await expect.element(tooltip).toHaveTextContent('Delete'); + }); + + it('hides the tooltip when the pointer leaves the trigger', async () => { + render(TooltipTriggerWrapper, { text: 'Delete' }); + await page.getByRole('button', { name: 'Trigger' }).hover(); + await expect.element(page.getByRole('tooltip')).toBeInTheDocument(); + await userEvent.unhover(await page.getByRole('button', { name: 'Trigger' }).element()); + await expect.element(page.getByRole('tooltip')).not.toBeInTheDocument(); + }); + + it('shows the tooltip when the trigger receives focus', async () => { + render(TooltipTriggerWrapper, { text: 'Delete' }); + const button = page.getByRole('button', { name: 'Trigger' }); + (await button.element()).focus(); + await expect.element(page.getByRole('tooltip')).toBeInTheDocument(); + }); + + it('hides the tooltip when the trigger loses focus', async () => { + render(TooltipTriggerWrapper, { text: 'Delete' }); + const button = page.getByRole('button', { name: 'Trigger' }); + (await button.element()).focus(); + await expect.element(page.getByRole('tooltip')).toBeInTheDocument(); + (await button.element()).blur(); + await expect.element(page.getByRole('tooltip')).not.toBeInTheDocument(); + }); + + it('does not show a tooltip when text is null', async () => { + render(TooltipTriggerWrapper, { text: null }); + await page.getByRole('button', { name: 'Trigger' }).hover(); + expect(page.getByRole('tooltip').query()).toBeNull(); + }); + + it('renders the tooltip in a portal attached to , not inline in the trigger', async () => { + render(TooltipTriggerWrapper, { text: 'Delete' }); + await page.getByRole('button', { name: 'Trigger' }).hover(); + const tooltipEl = (await page.getByRole('tooltip').element()) as HTMLElement; + const triggerEl = (await page + .getByRole('button', { name: 'Trigger' }) + .element()) as HTMLElement; + // The popup is portaled: it must not be a descendant of the trigger wrapper. + expect(triggerEl.contains(tooltipEl)).toBe(false); + // It is mounted into a host div that is a direct child of . + expect(tooltipEl.parentElement?.parentElement).toBe(document.body); + }); + + it('portals the tooltip into a ancestor so it escapes the modal', async () => { + render(TooltipTriggerDialogWrapper, { text: 'Delete' }); + const dialogEl = document.querySelector('dialog'); + expect(dialogEl).not.toBeNull(); + await page.getByRole('button', { name: 'Trigger' }).hover(); + const tooltipEl = (await page.getByRole('tooltip').element()) as HTMLElement; + // The popup must be inside the dialog (top layer), not attached to . + expect(dialogEl!.contains(tooltipEl)).toBe(true); + }); +}); diff --git a/src/lib/components/__tests__/TooltipTriggerDialogWrapper.svelte b/src/lib/components/__tests__/TooltipTriggerDialogWrapper.svelte new file mode 100644 index 00000000..3086e3e4 --- /dev/null +++ b/src/lib/components/__tests__/TooltipTriggerDialogWrapper.svelte @@ -0,0 +1,18 @@ + + + + + + + diff --git a/src/lib/components/__tests__/TooltipTriggerWrapper.svelte b/src/lib/components/__tests__/TooltipTriggerWrapper.svelte new file mode 100644 index 00000000..83ad42c6 --- /dev/null +++ b/src/lib/components/__tests__/TooltipTriggerWrapper.svelte @@ -0,0 +1,13 @@ + + + + + diff --git a/src/lib/components/catalog/CatalogBrowser.svelte b/src/lib/components/catalog/CatalogBrowser.svelte index 4ce670a5..15fe285e 100644 --- a/src/lib/components/catalog/CatalogBrowser.svelte +++ b/src/lib/components/catalog/CatalogBrowser.svelte @@ -260,27 +260,28 @@
{m.trino_catalog_browser()} - + + +
{#if catalogsLoading} diff --git a/src/lib/components/editor/MonacoEditor.svelte b/src/lib/components/editor/MonacoEditor.svelte index 65a57c93..64b64d75 100644 --- a/src/lib/components/editor/MonacoEditor.svelte +++ b/src/lib/components/editor/MonacoEditor.svelte @@ -2,6 +2,7 @@ import { onMount, onDestroy } from 'svelte'; import { browser } from '$app/environment'; import { theme } from '$lib/theme.svelte'; + import { getLocale } from '$lib/paraglide/runtime.js'; import { registerTrinoSql, setCompletionDefaultsGetter, @@ -133,7 +134,6 @@ // Start loading in parallel with the rest of the page — not deferred to onMount. // Guarded by `browser` because SvelteKit evaluates component scripts on the server too. const workerImport = browser ? import('monaco-editor/esm/vs/editor/editor.worker?worker') : null; - const monacoImport = browser ? import('monaco-editor') : null; function toMonacoTheme(t: string): string { return t === 'dark' ? 'vs-dark' : 'vs'; @@ -143,14 +143,23 @@ monaco?.editor.setTheme(toMonacoTheme(theme.current)); }); + const cleanups: (() => void)[] = []; + onMount(async () => { + // Load Monaco's NLS bundle for the active locale. Static import strings are + // required — Vite cannot bundle bare-specifier template literals at build time. + if (getLocale() === 'de') { + // @ts-expect-error — Monaco ESM nls bundle has no types + await import('monaco-editor/esm/nls.messages.de.js'); + } + // By the time onMount fires the imports are likely already resolved. const EditorWorker = (await workerImport!).default; self.MonacoEnvironment = { getWorker: () => new EditorWorker() }; - monaco = await monacoImport!; + monaco = await import('monaco-editor'); setCompletionDefaultsGetter(() => ({ catalog: defaultCatalog || undefined, @@ -227,9 +236,86 @@ run: onExecuteAll }); } + + // Ctrl+Mouse Wheel — zoom via built-in command (capture phase on document, + // because Monaco's internal handler calls stopPropagation on wheel events, + // so a container-level listener never fires) + const onWheel = (e: WheelEvent) => { + if ((e.ctrlKey || e.metaKey) && container.contains(e.target as Node)) { + e.preventDefault(); + editor?.trigger( + 'keyboard', + e.deltaY < 0 ? 'editor.action.fontZoomIn' : 'editor.action.fontZoomOut', + {} + ); + } + }; + document.addEventListener('wheel', onWheel, { capture: true, passive: false }); + cleanups.push(() => document.removeEventListener('wheel', onWheel, { capture: true })); + + // Prevent browser zoom & invoke font zoom for any keys Monaco doesn't handle + const handleZoomKeys = (e: KeyboardEvent) => { + if (!editor?.hasTextFocus()) return; + if (!(e.ctrlKey || e.metaKey)) return; + let command: string | null = null; + if (e.key === '=' || e.key === '+' || e.code === 'NumpadAdd') { + command = 'editor.action.fontZoomIn'; + } else if (e.key === '-' || e.code === 'NumpadSubtract') { + command = 'editor.action.fontZoomOut'; + } else if (e.key === '0' || e.code === 'Numpad0') { + command = 'editor.action.fontZoomReset'; + } + if (command) { + if (!e.defaultPrevented) editor?.trigger('keyboard', command, {}); + e.preventDefault(); + } + }; + document.addEventListener('keydown', handleZoomKeys); + cleanups.push(() => document.removeEventListener('keydown', handleZoomKeys)); + + // Bind keyboard shortcuts to the built-in font zoom commands + const zoomDisposable = monaco!.editor.addKeybindingRules([ + { + keybinding: monaco!.KeyMod.CtrlCmd | monaco!.KeyCode.Equal, + command: 'editor.action.fontZoomIn', + when: 'editorFocus' + }, + { + keybinding: monaco!.KeyMod.CtrlCmd | monaco!.KeyMod.Shift | monaco!.KeyCode.Equal, + command: 'editor.action.fontZoomIn', + when: 'editorFocus' + }, + { + keybinding: monaco!.KeyMod.CtrlCmd | monaco!.KeyCode.NumpadAdd, + command: 'editor.action.fontZoomIn', + when: 'editorFocus' + }, + { + keybinding: monaco!.KeyMod.CtrlCmd | monaco!.KeyCode.Minus, + command: 'editor.action.fontZoomOut', + when: 'editorFocus' + }, + { + keybinding: monaco!.KeyMod.CtrlCmd | monaco!.KeyCode.NumpadSubtract, + command: 'editor.action.fontZoomOut', + when: 'editorFocus' + }, + { + keybinding: monaco!.KeyMod.CtrlCmd | monaco!.KeyCode.Digit0, + command: 'editor.action.fontZoomReset', + when: 'editorFocus' + }, + { + keybinding: monaco!.KeyMod.CtrlCmd | monaco!.KeyCode.Numpad0, + command: 'editor.action.fontZoomReset', + when: 'editorFocus' + } + ]); + cleanups.push(() => zoomDisposable.dispose()); }); onDestroy(() => { + cleanups.forEach((fn) => fn()); editor?.dispose(); }); diff --git a/src/lib/components/editor/TextEditor.svelte b/src/lib/components/editor/TextEditor.svelte new file mode 100644 index 00000000..db870cf3 --- /dev/null +++ b/src/lib/components/editor/TextEditor.svelte @@ -0,0 +1,306 @@ + + +
+ {#if !browser || !ready} +
{displayValue}
+ {/if} +
diff --git a/src/lib/components/layout/NavigationProgress.svelte b/src/lib/components/layout/NavigationProgress.svelte new file mode 100644 index 00000000..bbee383d --- /dev/null +++ b/src/lib/components/layout/NavigationProgress.svelte @@ -0,0 +1,40 @@ + + +{#if active} +
+ + {m.navigation_loading()} +
+{/if} diff --git a/src/lib/components/layout/header/LanguageSwitcher.svelte b/src/lib/components/layout/header/LanguageSwitcher.svelte index 445e0044..4288d1f1 100644 --- a/src/lib/components/layout/header/LanguageSwitcher.svelte +++ b/src/lib/components/layout/header/LanguageSwitcher.svelte @@ -26,22 +26,27 @@ } - + +
storage.toggleSelect(file.key, e.ctrlKey || e.metaKey)} - ondblclick={() => storage.executeAction('preview')} + ondblclick={() => { + if (isArchive) { + void storage.archive.enterArchive(file.key); + } else { + storage.executeAction('preview'); + } + }} oncontextmenu={(e) => storage.openContextMenu(e, file.key)} > diff --git a/src/lib/components/storage/explorer/FolderRow.svelte b/src/lib/components/storage/explorer/FolderRow.svelte index 5ec0645c..83d00d8a 100644 --- a/src/lib/components/storage/explorer/FolderRow.svelte +++ b/src/lib/components/storage/explorer/FolderRow.svelte @@ -4,6 +4,13 @@ import { keyToName } from '$lib/storage/utils.js'; import type { StorageObject } from '$lib/storage/types.js'; import { getStorageState } from '$lib/storage/context.js'; + import { storageCutCopyEnabled } from '$lib/client/feature-flags.js'; + import { + handleRowDragStart, + parseStorageDropKeys, + canStorageDrop + } from '$lib/storage/drag-handlers.js'; + import * as m from '$lib/paraglide/messages.js'; interface Props { folder: StorageObject; @@ -15,26 +22,73 @@ const selected = $derived(storage.selectedKeys.has(folder.key)); const isCtx = $derived(storage.contextMenu?.key === folder.key); + const isCut = $derived(storage.isCutKey(folder.key)); + + let dragOver = $state(false); + + function handleDragStart(e: DragEvent) { + handleRowDragStart(e, folder.key, storage); + } + + function handleDragOver(e: DragEvent) { + if (!canStorageDrop(storage)) return; + // Don't allow dropping onto a selected folder (moving into itself) + if (storage.selectedKeys.has(folder.key)) return; + e.preventDefault(); + e.stopPropagation(); + if (e.dataTransfer) e.dataTransfer.dropEffect = 'move'; + dragOver = true; + } + + function handleDragLeave() { + dragOver = false; + } + + function handleDrop(e: DragEvent) { + dragOver = false; + if (!canStorageDrop(storage)) return; + e.preventDefault(); + e.stopPropagation(); + const keys = parseStorageDropKeys(e); + if (!keys) return; + // Don't drop onto a selected folder + if (keys.includes(folder.key)) return; + // Move items into this folder + void storage.performMove(folder.key, keys); + } { if (storage.selectionMode || e.ctrlKey || e.metaKey) { storage.toggleSelect(folder.key, true); + } else if (storage.archive.isInArchive) { + storage.archive.navigateInArchive(folder.key); } else { storage.navigate(folder.key); } }} ondblclick={(e) => { if (e.ctrlKey || e.metaKey) { - storage.navigate(folder.key); + if (storage.archive.isInArchive) { + storage.archive.navigateInArchive(folder.key); + } else { + storage.navigate(folder.key); + } } }} oncontextmenu={(e) => storage.openContextMenu(e, folder.key)} @@ -52,20 +106,21 @@ diff --git a/src/lib/components/storage/explorer/ObjectTable.svelte b/src/lib/components/storage/explorer/ObjectTable.svelte index d97cbd87..d728cfda 100644 --- a/src/lib/components/storage/explorer/ObjectTable.svelte +++ b/src/lib/components/storage/explorer/ObjectTable.svelte @@ -2,6 +2,7 @@ import * as m from '$lib/paraglide/messages.js'; import IconArrowBack from 'virtual:icons/material-symbols/arrow-back'; import IconFolderOpen from 'virtual:icons/material-symbols/folder-open'; + import IconWarning from 'virtual:icons/material-symbols/warning'; import SelectionToolbar from './SelectionToolbar.svelte'; import FolderRow from './FolderRow.svelte'; import FileRow from './FileRow.svelte'; @@ -14,17 +15,181 @@ if (selectAllEl) selectAllEl.indeterminate = storage.someSelected; }); + import { parseStorageDropKeys, canStorageDrop } from '$lib/storage/drag-handlers.js'; + function navigateUp() { + if (storage.archive.isInArchive) { + storage.archive.navigateUpFromArchive(); + return; + } if (!storage.prefix) return; const withoutTrailing = storage.prefix.slice(0, -1); const lastSlash = withoutTrailing.lastIndexOf('/'); storage.navigate(lastSlash === -1 ? '' : withoutTrailing.slice(0, lastSlash + 1)); } + + function parentPrefix(): string { + if (!storage.prefix) return ''; + const withoutTrailing = storage.prefix.slice(0, -1); + const lastSlash = withoutTrailing.lastIndexOf('/'); + return lastSlash === -1 ? '' : withoutTrailing.slice(0, lastSlash + 1); + } + + let tableDragOver = $state(false); + let parentDragOver = $state(false); + let emptyDragOver = $state(false); + + let scrollContainer = $state(null); + let autoScrollAnimFrame = $state(null); + + const EDGE_THICKNESS = 40; + const BASE_SCROLL_SPEED = 3; + const MAX_SCROLL_SPEED = 8; + + let headerEl = $state(null); + + function stopAutoScroll() { + if (autoScrollAnimFrame !== null) { + cancelAnimationFrame(autoScrollAnimFrame); + autoScrollAnimFrame = null; + } + } + + function contentEdgeY(clientY: number): number | null { + const container = scrollContainer; + if (!container) return null; + const bodyTop = headerEl + ? headerEl.getBoundingClientRect().bottom + : container.getBoundingClientRect().top; + return clientY - bodyTop; + } + + function handleTableDragOver(e: DragEvent) { + if (!canStorageDrop(storage)) return; + if (!e.dataTransfer?.types.includes('application/x-storage-keys')) return; + e.preventDefault(); + if (e.dataTransfer) e.dataTransfer.dropEffect = 'move'; + tableDragOver = true; + + const container = scrollContainer; + if (!container) return; + const edgeY = contentEdgeY(e.clientY); + if (edgeY === null) return; + const el = container as HTMLElement; + if (edgeY < EDGE_THICKNESS && el.scrollTop > 0) { + const factor = 1 - edgeY / EDGE_THICKNESS; + const speed = BASE_SCROLL_SPEED + (MAX_SCROLL_SPEED - BASE_SCROLL_SPEED) * factor; + stopAutoScroll(); + function tick() { + const newTop = el.scrollTop - speed; + if (newTop <= 0) { + el.scrollTop = 0; + stopAutoScroll(); + return; + } + el.scrollTop = newTop; + autoScrollAnimFrame = requestAnimationFrame(tick); + } + autoScrollAnimFrame = requestAnimationFrame(tick); + } else { + const rect = el.getBoundingClientRect(); + const y = e.clientY - rect.top; + if (y > rect.height - EDGE_THICKNESS && el.scrollTop < el.scrollHeight - el.clientHeight) { + const factor = (y - (rect.height - EDGE_THICKNESS)) / EDGE_THICKNESS; + const speed = BASE_SCROLL_SPEED + (MAX_SCROLL_SPEED - BASE_SCROLL_SPEED) * factor; + stopAutoScroll(); + function tick() { + const newTop = el.scrollTop + speed; + const maxScroll = el.scrollHeight - el.clientHeight; + if (newTop >= maxScroll) { + el.scrollTop = maxScroll; + stopAutoScroll(); + return; + } + el.scrollTop = newTop; + autoScrollAnimFrame = requestAnimationFrame(tick); + } + autoScrollAnimFrame = requestAnimationFrame(tick); + } else { + stopAutoScroll(); + } + } + } + + function handleTableDragLeave(e: DragEvent) { + // Only clear if we're leaving the table container entirely + const related = e.relatedTarget as Node | null; + if (related && (e.currentTarget as HTMLElement).contains(related)) return; + stopAutoScroll(); + tableDragOver = false; + } + + function handleTableDrop(e: DragEvent) { + stopAutoScroll(); + tableDragOver = false; + if (!canStorageDrop(storage)) return; + e.preventDefault(); + const keys = parseStorageDropKeys(e); + if (!keys) return; + void storage.performMove(storage.prefix, keys); + } + + function handleParentDragOver(e: DragEvent) { + if (!canStorageDrop(storage) || !storage.prefix) return; + e.preventDefault(); + if (e.dataTransfer) e.dataTransfer.dropEffect = 'move'; + parentDragOver = true; + } + + function handleParentDragLeave() { + parentDragOver = false; + } + + function handleParentDrop(e: DragEvent) { + parentDragOver = false; + if (!canStorageDrop(storage) || !storage.prefix) return; + e.preventDefault(); + const keys = parseStorageDropKeys(e); + if (!keys) return; + void storage.performMove(parentPrefix(), keys); + } + + function handleEmptyDragOver(e: DragEvent) { + if (!canStorageDrop(storage)) return; + if (!e.dataTransfer?.types.includes('application/x-storage-keys')) return; + e.preventDefault(); + e.stopPropagation(); + if (e.dataTransfer) e.dataTransfer.dropEffect = 'move'; + emptyDragOver = true; + } + + function handleEmptyDragLeave() { + emptyDragOver = false; + } + + function handleEmptyDrop(e: DragEvent) { + emptyDragOver = false; + if (!canStorageDrop(storage)) return; + e.preventDefault(); + e.stopPropagation(); + const keys = parseStorageDropKeys(e); + if (!keys) return; + void storage.performMove(storage.prefix, keys); + } -
+
@@ -48,38 +60,21 @@ /> -
- {#if kind === 'image'} -
+
{formatFileSize(file.size)} - +
+ +
-
- +
+ +
- + @@ -58,7 +223,15 @@ {#if storage.prefix} - + {/if} - - {#each storage.folders as folder (folder.key)} - - {/each} - - - {#each storage.files as file (file.key)} - - {/each} + {#if storage.loading && storage.folders.length === 0 && storage.files.length === 0} + {#each [75, 60, 85, 45, 90] as width, i (i)} + + + + + + + + {/each} + {/if} - - {#if storage.folders.length === 0 && storage.files.length === 0} + {#if storage.archive.archiveTooLarge} + - + {:else} + + {#each storage.folders as folder (folder.key)} + + {/each} + + + {#each storage.files as file (file.key)} + + {/each} + + + {#if !storage.loading && storage.folders.length === 0 && storage.files.length === 0} + storage.openEmptyContextMenu(e)} + > + + + {/if} {/if}
@@ -70,24 +243,54 @@
- +
+
diff --git a/src/lib/components/storage/explorer/OperationsButton.svelte b/src/lib/components/storage/explorer/OperationsButton.svelte new file mode 100644 index 00000000..4056c44b --- /dev/null +++ b/src/lib/components/storage/explorer/OperationsButton.svelte @@ -0,0 +1,504 @@ + + + e.key === 'Escape' && (dropdownOpen = false)} /> + +{#if storage.operations.length > 0} + {#if dropdownOpen} +
(dropdownOpen = false)} + role="presentation" + aria-hidden="true" + >
+ {/if} +
+ +
+ +
+ + + {#if dropdownOpen} + + {/if} +
+{/if} diff --git a/src/lib/components/storage/explorer/SelectionToolbar.svelte b/src/lib/components/storage/explorer/SelectionToolbar.svelte index 91dd742f..693598e3 100644 --- a/src/lib/components/storage/explorer/SelectionToolbar.svelte +++ b/src/lib/components/storage/explorer/SelectionToolbar.svelte @@ -1,6 +1,7 @@ -{#if breadcrumbCtx} - {@const breadcrumbIsPinned = storage.bookmarks.isPinned( - breadcrumbCtx.bucket, - breadcrumbCtx.prefix - )} - {@const BreadcrumbPinIcon = breadcrumbIsPinned ? IconPushPin : IconPushPinOutline} - -
e.key === 'Escape' && closeBreadcrumbCtx()} - >
- -{/if} + {#snippet pinButton(bucket: string, prefix: string)} {@const pinned = storage.bookmarks.isPinned(bucket, prefix)} @@ -102,34 +260,38 @@ motion-safe:transition-[width] motion-safe:duration-150 motion-safe:group-hover:delay-700 " > - + + {/snippet} @@ -141,19 +303,25 @@ flex min-w-0 flex-1 items-center gap-1 text-sm " > - {#if breadcrumbParts.length === 0} + {#if breadcrumbParts.length === 0 && !storage.archive.isInArchive} openBreadcrumbCtx(e, storage.bucket, '')} + ondragover={(e) => handleBreadcrumbDragOver(e, '')} + ondragleave={handleBreadcrumbDragLeave} + ondrop={(e) => handleBreadcrumbDrop(e, '')} > - {@render pinButton(storage.bucket, '')} @@ -165,10 +333,16 @@ text-base-content/70 hover:bg-base-200 hover:text-base-content flex shrink-0 items-center gap-1.5 rounded-sm px-1.5 py-0.5 transition-colors hover:cursor-pointer + {dropTargetPrefix === '' + ? 'bg-primary/20 outline-primary/50 outline -outline-offset-2' + : ''} " title={storage.bucket} - onclick={() => storage.navigate('')} + onclick={() => navigateS3('')} oncontextmenu={(e) => openBreadcrumbCtx(e, storage.bucket, '')} + ondragover={(e) => handleBreadcrumbDragOver(e, '')} + ondragleave={handleBreadcrumbDragLeave} + ondrop={(e) => handleBreadcrumbDrop(e, '')} > {/if} {#if collapsedParts.length > 0} -
diff --git a/src/lib/components/storage/explorer/TabBar.svelte b/src/lib/components/storage/explorer/TabBar.svelte new file mode 100644 index 00000000..60b74c87 --- /dev/null +++ b/src/lib/components/storage/explorer/TabBar.svelte @@ -0,0 +1,402 @@ + + + + +{#if tabsState.hasTabs} +
+ +
+ {#each tabsState.tabs as tab, idx (tab.id)} + {@const isActive = tab.id === tabsState.activeTabId} + {#if renamingId === tab.id} +
+ + +
+ {:else} + + {/if} + {/each} + + + + + +
+ + + {#if isOverflowLeft} + + {/if} + + + {#if isOverflowRight} + + {/if} +
+{/if} + + diff --git a/src/lib/components/storage/explorer/TabBar.svelte.spec.ts b/src/lib/components/storage/explorer/TabBar.svelte.spec.ts new file mode 100644 index 00000000..7324aad1 --- /dev/null +++ b/src/lib/components/storage/explorer/TabBar.svelte.spec.ts @@ -0,0 +1,211 @@ +import { page, userEvent } from 'vitest/browser'; +import { describe, expect, it, vi, beforeEach } from 'vitest'; +import { render } from 'vitest-browser-svelte'; +import TabBarWrapper from './__tests__/TabBarWrapper.svelte'; +import { TabsState } from '$lib/storage/tabs.svelte.js'; +import { StorageState } from '$lib/storage/state.svelte.js'; + +// ── Helpers ────────────────────────────────────────────────────────────────── + +function makeStorage(bucket = 'test-bucket', prefix = ''): StorageState { + const state = new StorageState({ connected: true }); + state.bucket = bucket; + state.prefix = prefix; + state.objects = { objects: [], hasNextPage: false, currentPage: 1, pageSize: 25 }; + return state; +} + +function makeTabsState(storage: StorageState, tabCount = 2): TabsState { + const ts = new TabsState(storage, { persistEnabled: false }); + ts.ensureInitialTab(); + for (let i = 1; i < tabCount; i++) { + ts.addTab(); + } + return ts; +} + +function renderTabBar(storage: StorageState, tabsState: TabsState) { + return render(TabBarWrapper, { storage, tabsState }); +} + +// ── Tests ───────────────────────────────────────────────────────────────────── + +describe('TabBar', () => { + beforeEach(() => { + localStorage.clear(); + }); + + it('renders a tab for each entry in tabsState.tabs', async () => { + const storage = makeStorage('bucket-a'); + const tabsState = makeTabsState(storage, 2); + renderTabBar(storage, tabsState); + + const tabs = page.getByRole('tab'); + // 2 tabs rendered + await expect.element(tabs.nth(0)).toBeInTheDocument(); + await expect.element(tabs.nth(1)).toBeInTheDocument(); + }); + + it('marks the active tab with aria-selected="true"', async () => { + const storage = makeStorage('bucket-a'); + const tabsState = makeTabsState(storage, 2); + renderTabBar(storage, tabsState); + + const activeTab = page.getByRole('tab', { selected: true }); + await expect.element(activeTab).toBeInTheDocument(); + }); + + it('has a tablist with an accessible label', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + renderTabBar(storage, tabsState); + + await expect.element(page.getByRole('tablist')).toBeInTheDocument(); + }); + + it('renders a "New Tab" plus button', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + renderTabBar(storage, tabsState); + + await expect.element(page.getByRole('button', { name: 'New Tab' })).toBeInTheDocument(); + }); + + it('calls addTab when the plus button is clicked', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + const spy = vi.spyOn(tabsState, 'addTab'); + renderTabBar(storage, tabsState); + + await page.getByRole('button', { name: 'New Tab' }).click(); + + expect(spy).toHaveBeenCalled(); + }); + + it('calls switchTo with the correct id when a non-active tab is clicked', async () => { + const storage = makeStorage('bucket', ''); + const tabsState = makeTabsState(storage, 2); + // After makeTabsState(2): tabs[0] is the initial tab (not active), tabs[1] is active + const spy = vi.spyOn(tabsState, 'switchTo'); + renderTabBar(storage, tabsState); + + // Click the first tab (not the active one) + await page.getByRole('tab').nth(0).click(); + + expect(spy).toHaveBeenCalledWith(tabsState.tabs[0].id); + }); + + it('shows close buttons when multiple tabs exist', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + renderTabBar(storage, tabsState); + + // Close tab buttons have aria-label="Close tab" + const closeButtons = page.getByRole('button', { name: 'Close tab' }); + await expect.element(closeButtons.first()).toBeInTheDocument(); + }); + + it('calls closeTab when a close button is clicked', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + const spy = vi.spyOn(tabsState, 'closeTab'); + renderTabBar(storage, tabsState); + + await page.getByRole('button', { name: 'Close tab' }).first().click(); + + expect(spy).toHaveBeenCalled(); + }); + + it('opens a context menu on right-click of a tab', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + renderTabBar(storage, tabsState); + + await page.getByRole('tab').first().click({ button: 'right' }); + + await expect.element(page.getByRole('menu')).toBeInTheDocument(); + }); + + it('context menu contains Rename tab and Close tab options', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + renderTabBar(storage, tabsState); + + await page.getByRole('tab').first().click({ button: 'right' }); + + await expect.element(page.getByRole('menuitem', { name: 'Rename tab' })).toBeInTheDocument(); + await expect.element(page.getByRole('menuitem', { name: 'Close tab' })).toBeInTheDocument(); + }); + + it('calls renameTab via context menu rename action', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + const spy = vi.spyOn(tabsState, 'renameTab'); + renderTabBar(storage, tabsState); + + const firstTabId = tabsState.tabs[0].id; + await page.getByRole('tab').first().click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Rename tab' }).click(); + + // The rename input should appear (context menu closes and rename mode starts) + await expect.element(page.getByRole('textbox', { name: 'Rename tab' })).toBeInTheDocument(); + + await page.getByRole('textbox', { name: 'Rename tab' }).fill('Renamed'); + await userEvent.keyboard('{Enter}'); + + expect(spy).toHaveBeenCalledWith(firstTabId, 'Renamed'); + }); + + it('shows rename input on double-click of a tab', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + renderTabBar(storage, tabsState); + + await page.getByRole('tab').first().dblClick(); + + await expect.element(page.getByRole('textbox', { name: 'Rename tab' })).toBeInTheDocument(); + }); + + it('commits rename on Enter key', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + const spy = vi.spyOn(tabsState, 'renameTab'); + renderTabBar(storage, tabsState); + + const firstTabId = tabsState.tabs[0].id; + await page.getByRole('tab').first().dblClick(); + + await page.getByRole('textbox', { name: 'Rename tab' }).fill('My New Name'); + await userEvent.keyboard('{Enter}'); + + expect(spy).toHaveBeenCalledWith(firstTabId, 'My New Name'); + }); + + it('cancels rename on Escape key without calling renameTab', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + const spy = vi.spyOn(tabsState, 'renameTab'); + renderTabBar(storage, tabsState); + + await page.getByRole('tab').first().dblClick(); + + await page.getByRole('textbox', { name: 'Rename tab' }).fill('Something'); + await userEvent.keyboard('{Escape}'); + + expect(spy).not.toHaveBeenCalled(); + await expect.element(page.getByRole('textbox', { name: 'Rename tab' })).not.toBeInTheDocument(); + }); + + it('calls closeTab via context menu close action', async () => { + const storage = makeStorage(); + const tabsState = makeTabsState(storage, 2); + const spy = vi.spyOn(tabsState, 'closeTab'); + const firstTabId = tabsState.tabs[0].id; + renderTabBar(storage, tabsState); + + await page.getByRole('tab').first().click({ button: 'right' }); + await page.getByRole('menuitem', { name: 'Close tab' }).click(); + + expect(spy).toHaveBeenCalledWith(firstTabId); + }); +}); diff --git a/src/lib/components/storage/explorer/__tests__/ContextMenu.svelte.spec.ts b/src/lib/components/storage/explorer/__tests__/ContextMenu.svelte.spec.ts index 2e86509d..6f823e49 100644 --- a/src/lib/components/storage/explorer/__tests__/ContextMenu.svelte.spec.ts +++ b/src/lib/components/storage/explorer/__tests__/ContextMenu.svelte.spec.ts @@ -113,7 +113,7 @@ describe('ContextMenu', () => { selectedKeys: ['test.txt'] }); const spy = vi.spyOn(state, 'closeContextMenu'); - render(ContextMenuWrapper, { state }); + render(ContextMenuWrapper, { state, title: 'Menu' }); await page.getByRole('menuitem', { name: 'Close' }).click(); expect(spy).toHaveBeenCalled(); diff --git a/src/lib/components/storage/explorer/__tests__/ContextMenuWrapper.svelte b/src/lib/components/storage/explorer/__tests__/ContextMenuWrapper.svelte index 8307de87..5defe339 100644 --- a/src/lib/components/storage/explorer/__tests__/ContextMenuWrapper.svelte +++ b/src/lib/components/storage/explorer/__tests__/ContextMenuWrapper.svelte @@ -6,10 +6,11 @@ interface Props { state: StorageState; + title?: string; } - let { state }: Props = $props(); + let { state, title }: Props = $props(); untrack(() => setStorageState(state)); - + diff --git a/src/lib/components/storage/explorer/__tests__/FileExplorerWrapper.svelte b/src/lib/components/storage/explorer/__tests__/FileExplorerWrapper.svelte index 7106df4f..2c577d6b 100644 --- a/src/lib/components/storage/explorer/__tests__/FileExplorerWrapper.svelte +++ b/src/lib/components/storage/explorer/__tests__/FileExplorerWrapper.svelte @@ -1,7 +1,8 @@ diff --git a/src/lib/components/storage/explorer/__tests__/FileRow.svelte.spec.ts b/src/lib/components/storage/explorer/__tests__/FileRow.svelte.spec.ts index 24f0be8c..d0d07a27 100644 --- a/src/lib/components/storage/explorer/__tests__/FileRow.svelte.spec.ts +++ b/src/lib/components/storage/explorer/__tests__/FileRow.svelte.spec.ts @@ -74,7 +74,7 @@ describe('FileRow', () => { const state = createState([file]); render(FileRowWrapper, { state, file }); - await expect.element(page.getByText('unknown-file')).toBeInTheDocument(); + await expect.element(page.getByText('unknown-file').first()).toBeInTheDocument(); }); it('should show checkbox when showCheckboxes is true', async () => { @@ -124,13 +124,62 @@ describe('FileRow', () => { expect(spy).toHaveBeenCalledWith('click.txt', false); }); + async function dblClickRow(): Promise { + const row = page.getByRole('row').element(); + row.dispatchEvent(new MouseEvent('dblclick', { bubbles: true })); + } + it('should call executeAction preview on double click', async () => { const file = makeFile({ key: 'dbl.txt', contentType: 'text/plain' }); const state = createState([file]); const spy = vi.spyOn(state, 'executeAction'); render(FileRowWrapper, { state, file }); - await page.getByRole('row').dblClick(); + await dblClickRow(); + expect(spy).toHaveBeenCalledWith('preview'); + }); + + it('should call enterArchive on double click for zip files', async () => { + const file = makeFile({ key: 'archive.zip', contentType: 'application/zip' }); + const state = createState([file]); + const spy = vi.spyOn(state.archive, 'enterArchive'); + render(FileRowWrapper, { state, file }); + + await dblClickRow(); + expect(spy).toHaveBeenCalledWith('archive.zip'); + }); + + it('should call enterArchive on double click for tar.gz files', async () => { + const file = makeFile({ key: 'bundle.tar.gz', contentType: 'application/gzip' }); + const state = createState([file]); + const spy = vi.spyOn(state.archive, 'enterArchive'); + render(FileRowWrapper, { state, file }); + + await dblClickRow(); + expect(spy).toHaveBeenCalledWith('bundle.tar.gz'); + }); + + it('should call enterArchive on double click for nested archive inside an archive', async () => { + const file = makeFile({ key: 'nested.zip', contentType: undefined }); + const state = createState([file]); + state.archive.archiveKey = 'outer.zip'; + state.archive.archivePrefix = ''; + const spy = vi.spyOn(state.archive, 'enterArchive'); + render(FileRowWrapper, { state, file }); + + await dblClickRow(); + expect(spy).toHaveBeenCalledWith('nested.zip'); + }); + + it('should call executeAction preview on double click for non-archive file inside archive', async () => { + const file = makeFile({ key: 'readme.txt', contentType: 'text/plain' }); + const state = createState([file]); + state.archive.archiveKey = 'outer.zip'; + state.archive.archivePrefix = ''; + const spy = vi.spyOn(state, 'executeAction'); + render(FileRowWrapper, { state, file }); + + await dblClickRow(); expect(spy).toHaveBeenCalledWith('preview'); }); diff --git a/src/lib/components/storage/explorer/__tests__/StorageBreadcrumb.svelte.spec.ts b/src/lib/components/storage/explorer/__tests__/StorageBreadcrumb.svelte.spec.ts index 3bbffaaa..c557470a 100644 --- a/src/lib/components/storage/explorer/__tests__/StorageBreadcrumb.svelte.spec.ts +++ b/src/lib/components/storage/explorer/__tests__/StorageBreadcrumb.svelte.spec.ts @@ -191,16 +191,14 @@ describe('StorageBreadcrumb', () => { }); describe('pin/unpin', () => { - it('should show pin option in more options menu', async () => { + it('should show a pin control for the current location', async () => { const state = createState(); render(StorageBreadcrumbWrapper, { state }); - // The more options button exists - const moreBtn = page.getByRole('button', { name: /more options/i }); - await expect.element(moreBtn).toBeInTheDocument(); + await expect.element(page.getByRole('button', { name: 'Pin' })).toBeInTheDocument(); }); - it('should show unpin when current location is pinned', async () => { + it('should show unpin control when current location is pinned', async () => { const state = createState({ bucket: 'test-bucket', prefix: 'data/', @@ -208,35 +206,20 @@ describe('StorageBreadcrumb', () => { }); render(StorageBreadcrumbWrapper, { state }); - // The more menu should contain unpin - const menuItems = page.getByRole('menuitem'); - await expect.element(menuItems.first()).toBeInTheDocument(); + await expect.element(page.getByRole('button', { name: 'Unpin' })).toBeInTheDocument(); }); - it('should call pin via more options menu when not pinned', async () => { + it('should pin the current location', async () => { const state = createState({ bucket: 'test-bucket', prefix: 'data/' }); const spy = vi.spyOn(state.bookmarks, 'pin'); render(StorageBreadcrumbWrapper, { state }); - // Open the dropdown by focusing/clicking the trigger - const moreBtn = page.getByRole('button', { name: /more options/i }); - await moreBtn.click(); - - // DaisyUI dropdown uses focus to show content; click the menuitem - const menuItems = page.getByRole('menuitem'); - // Force the click by using element() - const el = menuItems.first(); - await el.click(); - - // If DaisyUI dropdown prevents click, try direct dispatch - if (!spy.mock.calls.length) { - const domEl = (await el.element()) as HTMLElement; - domEl.click(); - } + const pinButton = page.getByRole('button', { name: 'Pin' }).last(); + ((await pinButton.element()) as HTMLElement).click(); expect(spy).toHaveBeenCalledWith('test-bucket', 'data/'); }); - it('should call unpin via more options menu when pinned', async () => { + it('should unpin the current location', async () => { const state = createState({ bucket: 'test-bucket', prefix: 'data/', @@ -245,12 +228,8 @@ describe('StorageBreadcrumb', () => { const spy = vi.spyOn(state.bookmarks, 'unpin'); render(StorageBreadcrumbWrapper, { state }); - // Open the dropdown first - const moreBtn = page.getByRole('button', { name: /more options/i }); - await moreBtn.click(); - - const menuItem = page.getByRole('menuitem'); - await menuItem.first().click(); + const unpinButton = page.getByRole('button', { name: 'Unpin' }); + ((await unpinButton.element()) as HTMLElement).click(); expect(spy).toHaveBeenCalledWith('test-bucket', 'data/'); }); }); @@ -350,7 +329,7 @@ describe('StorageBreadcrumb', () => { const bucketEl = nav.getByText('test-bucket'); await bucketEl.click({ button: 'right' }); - const menuItem = page.getByRole('menuitem'); + const menuItem = page.getByRole('menuitem', { name: /pin/i }); await menuItem.first().click(); expect(spy).toHaveBeenCalledWith('test-bucket', ''); }); @@ -367,7 +346,7 @@ describe('StorageBreadcrumb', () => { const bucketEl = nav.getByText('test-bucket'); await bucketEl.click({ button: 'right' }); - const menuItem = page.getByRole('menuitem'); + const menuItem = page.getByRole('menuitem', { name: /unpin/i }); await menuItem.first().click(); expect(spy).toHaveBeenCalledWith('test-bucket', ''); }); @@ -391,9 +370,8 @@ describe('StorageBreadcrumb', () => { const backdrop = menuUl.previousElementSibling as HTMLElement; backdrop.dispatchEvent(new MouseEvent('mousedown', { bubbles: true })); - // Context menu should be closed - menuitem from ctx menu should be gone - // The only remaining menuitem should be from the more options dropdown - await expect.element(page.getByRole('menuitem')).toBeInTheDocument(); // the one in more options + // Context menu should be closed. + await expect.element(page.getByRole('menuitem').first()).not.toBeInTheDocument(); }); it('should open context menu on right-click of bucket with prefix', async () => { @@ -455,4 +433,68 @@ describe('StorageBreadcrumb', () => { await expect.element(moreBtn).not.toBeInTheDocument(); }); }); + + describe('archive mode', () => { + it('should show archive name when inside an archive', async () => { + const state = createState(); + state.archive.archiveKey = 'data.zip'; + render(StorageBreadcrumbWrapper, { state }); + + const nav = page.getByRole('navigation', { name: 'breadcrumb' }); + await expect.element(nav.getByText('data.zip')).toBeInTheDocument(); + }); + + it('should show internal path parts when navigating within archive', async () => { + const state = createState(); + state.archive.archiveKey = 'data.zip'; + state.archive.archivePrefix = 'music/videos/'; + render(StorageBreadcrumbWrapper, { state }); + + const nav = page.getByRole('navigation', { name: 'breadcrumb' }); + await expect + .element(nav.getByRole('button', { name: 'music', exact: true })) + .toBeInTheDocument(); + await expect.element(nav.getByText('videos')).toHaveAttribute('aria-current', 'page'); + }); + + it('should show nested archive entry when browsing nested archive', async () => { + const state = createState(); + state.archive.archiveKey = 'outer.zip'; + state.archive._restoreFullState({ + archiveKey: 'outer.zip', + archivePrefix: 'subdir/', + archiveNestedPath: 'inner.tar', + previousS3Prefix: '', + archiveLoading: false, + archiveTooLarge: false + }); + state.archive.archivePrefix = 'subdir/'; + render(StorageBreadcrumbWrapper, { state }); + + const nav = page.getByRole('navigation', { name: 'breadcrumb' }); + await expect.element(nav.getByText('outer.zip')).toBeInTheDocument(); + await expect.element(nav.getByText('inner.tar')).toBeInTheDocument(); + await expect.element(nav.getByText('subdir')).toBeInTheDocument(); + }); + + it('should call navigateInArchive when clicking breadcrumb folder inside archive', async () => { + const state = createState(); + state.archive.archiveKey = 'data.zip'; + state.archive.archivePrefix = 'music/videos/'; + const spy = vi.spyOn(state.archive, 'navigateInArchive'); + render(StorageBreadcrumbWrapper, { state }); + + const nav = page.getByRole('navigation', { name: 'breadcrumb' }); + await nav.getByRole('button', { name: 'music', exact: true }).click(); + expect(spy).toHaveBeenCalledWith('music/'); + }); + + it('should hide upload button when in archive mode', async () => { + const state = createState(); + state.archive.archiveKey = 'data.zip'; + render(StorageBreadcrumbWrapper, { state }); + + await expect.element(page.getByRole('button', { name: /upload/i })).not.toBeInTheDocument(); + }); + }); }); diff --git a/src/lib/components/storage/explorer/__tests__/StorageBreadcrumbWrapper.svelte b/src/lib/components/storage/explorer/__tests__/StorageBreadcrumbWrapper.svelte index 073599f2..3c73ae8f 100644 --- a/src/lib/components/storage/explorer/__tests__/StorageBreadcrumbWrapper.svelte +++ b/src/lib/components/storage/explorer/__tests__/StorageBreadcrumbWrapper.svelte @@ -1,15 +1,21 @@ diff --git a/src/lib/components/storage/explorer/__tests__/TabBarWrapper.svelte b/src/lib/components/storage/explorer/__tests__/TabBarWrapper.svelte new file mode 100644 index 00000000..ffebff1c --- /dev/null +++ b/src/lib/components/storage/explorer/__tests__/TabBarWrapper.svelte @@ -0,0 +1,21 @@ + + + diff --git a/src/lib/components/storage/explorer/file-icon/FileIconAndName.svelte b/src/lib/components/storage/explorer/file-icon/FileIconAndName.svelte new file mode 100644 index 00000000..c510f0e5 --- /dev/null +++ b/src/lib/components/storage/explorer/file-icon/FileIconAndName.svelte @@ -0,0 +1,38 @@ + + +
+ {@render renderIcon(config)} + {keyToName(file.key)} + {#if badge} + + {badge} + + {/if} +
+ +{#snippet renderIcon(cfg: IconConfig)} +