diff --git a/.github/workflows/docker-reusable.yml b/.github/workflows/docker-reusable.yml new file mode 100644 index 0000000..1c53f9e --- /dev/null +++ b/.github/workflows/docker-reusable.yml @@ -0,0 +1,181 @@ +name: Docker - Reusable + + +on: + workflow_call: + inputs: + docker_file: + default: docker/Dockerfile + description: Dockerfile + required: false + type: string + docker_repo: + default: codexstorage/codex-marketplace-ui + description: DockerHub repository + required: false + type: string + tag_latest: + default: true + description: Set latest tag for Docker images + required: false + type: boolean + tag_sha: + default: true + description: Set Git short commit as Docker tag + required: false + type: boolean + tag_suffix: + default: '' + description: Suffix for Docker images tag + required: false + type: string + + +env: + DOCKER_FILE: ${{ inputs.docker_file }} + DOCKER_REPO: ${{ inputs.docker_repo }} + TAG_LATEST: ${{ inputs.tag_latest }} + TAG_SHA: ${{ inputs.tag_sha }} + TAG_SUFFIX: ${{ inputs.tag_suffix }} + + +jobs: + # Build platform specific image + build: + strategy: + fail-fast: true + matrix: + target: + - os: linux + arch: amd64 + - os: linux + arch: arm64 + include: + - target: + os: linux + arch: amd64 + builder: ubuntu-22.04 + - target: + os: linux + arch: arm64 + builder: buildjet-4vcpu-ubuntu-2204-arm + + name: Build ${{ matrix.target.os }}/${{ matrix.target.arch }} + runs-on: ${{ matrix.builder }} + env: + PLATFORM: ${{ format('{0}/{1}', 'linux', matrix.target.arch) }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker - Meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKER_REPO }} + + - name: Docker - Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker - Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Docker - Build and Push by digest + id: build + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ env.DOCKER_FILE }} + platforms: ${{ env.PLATFORM }} + push: true + build-args: | + VITE_CODEX_API_URL=${{ secrets.VITE_CODEX_API_URL }} + VITE_GEO_IP_URL=${{ secrets.VITE_GEO_IP_URL }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,name=${{ env.DOCKER_REPO }},push-by-digest=true,name-canonical=true,push=true + + - name: Docker - Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Docker - Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ matrix.target.arch }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + + # Publish multi-platform image + publish: + name: Publish multi-platform image + runs-on: ubuntu-latest + needs: build + steps: + - name: Docker - Variables + run: | + # Adjust custom suffix when set and + if [[ -n "${{ env.TAG_SUFFIX }}" ]]; then + echo "TAG_SUFFIX=-${{ env.TAG_SUFFIX }}" >>$GITHUB_ENV + fi + # Disable SHA tags on tagged release + if [[ ${{ startsWith(github.ref, 'refs/tags/') }} == "true" ]]; then + echo "TAG_SHA=false" >>$GITHUB_ENV + fi + # Handle latest and latest-custom using raw + if [[ ${{ env.TAG_SHA }} == "false" ]]; then + echo "TAG_LATEST=false" >>$GITHUB_ENV + echo "TAG_RAW=true" >>$GITHUB_ENV + if [[ -z "${{ env.TAG_SUFFIX }}" ]]; then + echo "TAG_RAW_VALUE=latest" >>$GITHUB_ENV + else + echo "TAG_RAW_VALUE=latest-{{ env.TAG_SUFFIX }}" >>$GITHUB_ENV + fi + else + echo "TAG_RAW=false" >>$GITHUB_ENV + fi + + - name: Docker - Download digests + uses: actions/download-artifact@v4 + with: + pattern: digests-* + merge-multiple: true + path: /tmp/digests + + - name: Docker - Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker - Meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKER_REPO }} + flavor: | + latest=${{ env.TAG_LATEST }} + suffix=${{ env.TAG_SUFFIX }},onlatest=true + tags: | + type=semver,pattern={{version}} + type=raw,enable=${{ env.TAG_RAW }},value=latest + type=sha,enable=${{ env.TAG_SHA }} + + - name: Docker - Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Docker - Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.DOCKER_REPO }}@sha256:%s ' *) + + - name: Docker - Inspect image + run: | + docker buildx imagetools inspect ${{ env.DOCKER_REPO }}:${{ steps.meta.outputs.version }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..2159acb --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,28 @@ +name: Docker + + +on: + push: + branches: + - master + tags: + - 'v*.*.*' + paths-ignore: + - '**/*.md' + - '.gitignore' + - 'docker/**' + - '!docker/Dockerfile' + - '.github/**' + - '!.github/workflows/docker.yml' + - '!.github/workflows/docker-reusable.yml' + - 'LICENSE-*' + workflow_dispatch: + + +jobs: + build-and-push: + name: Build and Push + uses: ./.github/workflows/docker-reusable.yml + with: + tag_latest: ${{ github.ref_name == github.event.repository.default_branch || startsWith(github.ref, 'refs/tags/') }} + secrets: inherit diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 63b115f..bbde8c4 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -8,8 +8,8 @@ on: workflow_dispatch: env: - codex_version: v0.1.6 - circuit_version: v0.1.6 + codex_version: v0.1.7 + circuit_version: v0.1.7 marketplace_address: "0xfE822Df439d987849a90B64a4C0e26a297DBD47F" eth_provider: "https://rpc.testnet.codex.storage" VITE_CODEX_API_URL: ${{ secrets.VITE_CODEX_API_URL }} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..df68c31 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,47 @@ +# Variables +ARG BUILDER=node:22-alpine +ARG IMAGE=nginx:1.27-alpine-slim +ARG APP_USER=root +ARG BUILD_HOME=/app +ARG BUILD_OUT=dist +ARG APP_HOME=${BUILD_HOME} +ARG APP_PORT=${APP_PORT:-80} +ARG NGINX_TEMPLATE=docker/default.conf.template +ARG VITE_CODEX_API_URL=${VITE_CODEX_API_URL:-http://127.0.0.1:8080} +ARG VITE_GEO_IP_URL=${VITE_GEO_IP_URL:-http://127.0.0.1:8080} + + +# Build +FROM ${BUILDER} AS builder + +ARG APP_USER +ARG BUILD_HOME +ARG VITE_CODEX_API_URL +ARG VITE_GEO_IP_URL + +WORKDIR ${BUILD_HOME} +COPY --chown=${APP_USER}:${APP_USER} . . + +RUN npm install +RUN npm run build + + +# Create +FROM ${IMAGE} + +ARG APP_USER +ARG BUILD_HOME +ARG BUILD_OUT +ARG APP_HOME +ARG APP_PORT +ARG NGINX_TEMPLATE + +WORKDIR ${APP_HOME} +RUN mkdir /etc/nginx/templates +COPY ${NGINX_TEMPLATE} /etc/nginx/templates +COPY --chown=${APP_USER}:${APP_USER} --from=builder ${BUILD_HOME}/${BUILD_OUT} . + +ENV APP_HOME=${APP_HOME} +ENV APP_PORT=${APP_PORT} + +EXPOSE ${APP_PORT} diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..810617c --- /dev/null +++ b/docker/README.md @@ -0,0 +1,59 @@ +# Codex Marketplace UI Docker images + +## Description + + We are shipping Codex Marketplace UI as a Docker image as well. + + [Dockerfile](Dockerfile) is using multi-stage build and we use `alpine` image to speed up the build and to minimize the final Docker image size we are using a lightweight Nginx image. + + +## Build locally + + We can build image locally in the following way + 1. [Install Docker](https://docs.docker.com/engine/install) + + 2. Clone repository + ```shell + git clone https://github.com/codex-storage/codex-marketplace-ui + cd codex-marketplace-ui + ``` + + 3. Build the image + ```shell + # Variables + VITE_CODEX_API_URL= + VITE_GEO_IP_URL= + + # Build + docker build \ + --build-arg VITE_CODEX_API_URL=${VITE_CODEX_API_URL} \ + --build-arg VITE_GEO_IP_URL=${VITE_GEO_IP_URL} \ + --no-cache \ + -f docker/Dockerfile \ + -t codex-marketplace-ui:local . + ``` + + +## How to run + + Base [Nginx image](https://hub.docker.com/_/nginx) is [exposing](https://docs.docker.com/reference/dockerfile/#expose) port 80 and we can [publish](https://docs.docker.com/get-started/docker-concepts/running-containers/publishing-ports/) it to a custom local port + ```shell + docker run \ + --rm \ + --name codex-marketplace-ui \ + -p 3000:80 \ + codexstorage/codex-marketplace-ui:latest + ``` + + Access UI on http://localhost:3000. + + And we also can set Nginx custom port using `APP_PORT` variable. That is useful when use the `host` network mode for a container + ```shell + docker run \ + --rm \ + --name codex-marketplace-ui \ + --net=host \ + -e 'APP_PORT=3000' \ + -p 3000:3000 \ + codexstorage/codex-marketplace-ui:latest + ``` diff --git a/docker/default.conf.template b/docker/default.conf.template new file mode 100644 index 0000000..e4c09cd --- /dev/null +++ b/docker/default.conf.template @@ -0,0 +1,15 @@ +server { + listen ${APP_PORT}; + server_name localhost; + + root /usr/share/nginx/html; + + error_page 500 502 503 504 /50x.html; + + location / { + root ${APP_HOME}; + index index.html; + + try_files $uri $uri/ /index.html =404; + } +} diff --git a/e2e/download.spec.ts b/e2e/download.spec.ts new file mode 100644 index 0000000..ae7899e --- /dev/null +++ b/e2e/download.spec.ts @@ -0,0 +1,32 @@ +import { test, expect } from '@playwright/test'; +import { readFileSync } from 'fs'; +import path, { dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +test('download a file', async ({ page, browserName }) => { + // https://github.com/microsoft/playwright/issues/13037 + test.skip(browserName.toLowerCase() !== 'chromium', + `Test only for chromium!`); + + await page.goto('/dashboard'); + await page.locator('div').getByTestId("upload").setInputFiles([ + path.join(__dirname, "assets", 'chatgpt.jpg'), + ]); + await page.context().grantPermissions(["clipboard-read", "clipboard-write"]); + await page.locator('.files-fileActions > button:nth-child(3)').first().click(); + await page.getByRole('button', { name: 'Copy CID' }).click(); + const handle = await page.evaluateHandle(() => navigator.clipboard.readText()); + const cid = await handle.jsonValue() + await page.locator('.sheets-container > .backdrop').click(); + await page.getByPlaceholder('CID').click(); + await page.getByPlaceholder('CID').fill(cid); + const page1Promise = page.waitForEvent('popup'); + const downloadPromise = page.waitForEvent('download'); + await page.locator('div').filter({ hasText: /^Download a fileDownload$/ }).getByRole('button').click(); + const page1 = await page1Promise; + const download = await downloadPromise; + expect(await download.failure()).toBeNull() +}); \ No newline at end of file diff --git a/e2e/settings.spec.ts b/e2e/settings.spec.ts index 48db1dd..f1f16a9 100644 --- a/e2e/settings.spec.ts +++ b/e2e/settings.spec.ts @@ -6,4 +6,20 @@ test('update the log level', async ({ page }) => { await page.getByLabel('Log level').selectOption('TRACE'); await page.getByRole('main').locator('div').filter({ hasText: 'Log' }).getByRole('button').click(); await expect(page.locator('span').filter({ hasText: 'success ! The log level has' }).locator('b')).toBeVisible(); +}) + +test('update the URL with wrong URL applies', async ({ page }) => { + await page.goto('/dashboard'); + await page.getByRole('link', { name: 'Settings' }).click(); + await page.getByLabel('Codex client node URL').click(); + await page.getByLabel('Codex client node URL').fill('hello'); + await expect.soft(page.getByText("The URL is not valid")).toBeVisible() + await expect.soft(page.locator(".settings-url-button")).toBeDisabled() + await page.getByLabel('Codex client node URL').fill('http://127.0.0.1:8079'); + await expect.soft(page.getByText("The URL is not valid")).not.toBeVisible() + await expect.soft(page.locator(".settings-url-button")).not.toBeDisabled() + await page.getByRole('button', { name: 'Save changes' }).nth(1).click(); + await expect.soft(page.getByText("Cannot retrieve the data")).toBeVisible() + await page.getByLabel('Codex client node URL').fill('http://127.0.0.1:8080'); + await page.getByRole('button', { name: 'Save changes' }).nth(1).click(); }) \ No newline at end of file diff --git a/e2e/storage-requests.spec.ts b/e2e/storage-requests.spec.ts index 54dbcb4..3db89ab 100644 --- a/e2e/storage-requests.spec.ts +++ b/e2e/storage-requests.spec.ts @@ -30,7 +30,7 @@ test('select a uploaded cid when creating a storage request', async ({ page }) = await page.getByRole('link', { name: 'Purchases' }).click(); await page.getByRole('button', { name: 'Storage Request' }).click(); await page.getByPlaceholder('Select or type your CID').click(); - await page.getByText('N/A0').click(); + await page.locator('.dropdown-option').nth(1).click(); await expect(page.getByText('button[disabled]')).not.toBeVisible(); }) @@ -63,3 +63,15 @@ test('storage request navigation buttons', async ({ page }) => { await page.getByRole('button', { name: 'Finish' }).click(); await expect(page.locator('.modal--open')).not.toBeVisible(); }) + +test('remove the CID when the file is deleted', async ({ page }) => { + await page.goto('/dashboard'); + await page.getByRole('link', { name: 'Purchases' }).click(); + await page.getByRole('button', { name: 'Storage Request' }).click(); + await page.locator('div').getByTestId("upload").setInputFiles([ + path.join(__dirname, "assets", 'chatgpt.jpg'), + ]); + await expect(page.locator('#cid')).toHaveValue("zDvZRwzkvwapyNeL4mzw5gBsZvyn7x8F8Y9n4RYSC7ETBssDYpGe") + await page.locator('.uploadFile-infoRight .buttonIcon--small').click(); + await expect(page.locator('#cid')).toHaveValue("") +}) diff --git a/package-lock.json b/package-lock.json index 9a79969..d8558c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@codex-storage/marketplace-ui", - "version": "0.0.3", + "version": "0.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@codex-storage/marketplace-ui", - "version": "0.0.3", + "version": "0.0.7", "license": "MIT", "dependencies": { - "@codex-storage/marketplace-ui-components": "^0.0.22", + "@codex-storage/marketplace-ui-components": "^0.0.24", "@codex-storage/sdk-js": "^0.0.8", "@sentry/browser": "^8.32.0", "@sentry/react": "^8.31.0", @@ -58,11 +58,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" }, "engines": { @@ -70,28 +71,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.4", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", + "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.25.2", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", + "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.8", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.8", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -107,27 +110,29 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.6", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.25.6", + "@babel/types": "^7.25.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -136,26 +141,28 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -165,67 +172,74 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.25.6", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", + "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6" + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -235,11 +249,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.6", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.25.6" + "@babel/types": "^7.25.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -249,11 +264,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", + "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -263,11 +279,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.4", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz", + "integrity": "sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -305,28 +322,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.0", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.6", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.6", - "@babel/parser": "^7.25.6", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -335,12 +354,13 @@ } }, "node_modules/@babel/types": { - "version": "7.25.6", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -354,9 +374,9 @@ "dev": true }, "node_modules/@codex-storage/marketplace-ui-components": { - "version": "0.0.22", - "resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.22.tgz", - "integrity": "sha512-tzEmojhQv+6GGQ8PDCbZpUDce7Q7OUTSAZcRxhQI9GfbbaOCwMLIGgC499Xfl+5376lEhcYO0rAWJjqih3odfQ==", + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.24.tgz", + "integrity": "sha512-7YVpy70zC1rHxpUjFOt+gkhj1Rt9wG1Ls4hNtUzR4lFrICvCC8m4EuUg37FlgjTt2H9eLpVt1b090Wyz+CKeng==", "dependencies": { "lucide-react": "^0.441.0" }, @@ -600,12 +620,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.0.tgz", - "integrity": "sha512-W5lhqPUVPqhtc/ySvZI5Q8X2ztBOUgZ8LbAFy0JQgrXZs2xaILrUcNO3rQjwbLPfGK13+rZsDa1FpG+tqYkT5w==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.1.tgz", + "integrity": "sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==", "dev": true, "dependencies": { - "playwright": "1.48.0" + "playwright": "1.48.1" }, "bin": { "playwright": "cli.js" @@ -823,97 +843,97 @@ ] }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.33.1.tgz", - "integrity": "sha512-TW6/r+Gl5jiXv54iK1xZ3mlVgTS/jaBp4vcQ0xGMdgiQ3WchEPcFSeYovL+YHT3tSud0GZqVtDQCz+5i76puqA==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.35.0.tgz", + "integrity": "sha512-uj9nwERm7HIS13f/Q52hF/NUS5Al8Ma6jkgpfYGeppYvU0uSjPkwMogtqoJQNbOoZg973tV8qUScbcWY616wNA==", "dependencies": { - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry/core": "8.35.0", + "@sentry/types": "8.35.0", + "@sentry/utils": "8.35.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.33.1.tgz", - "integrity": "sha512-qauMRTm3qDaLqZ3ibI03cj4gLF40y0ij65nj+cns6iWxGCtPrO8tjvXFWuQsE7Aye9dGMnBgmv7uN+NTUtC3RA==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.35.0.tgz", + "integrity": "sha512-7bjSaUhL0bDArozre6EiIhhdWdT/1AWNWBC1Wc5w1IxEi5xF7nvF/FfvjQYrONQzZAI3HRxc45J2qhLUzHBmoQ==", "dependencies": { - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry/core": "8.35.0", + "@sentry/types": "8.35.0", + "@sentry/utils": "8.35.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.33.1.tgz", - "integrity": "sha512-fm4coIOjmanU29NOVN9MyaP4fUCOYytbtFqVSKRFNZQ/xAgNeySiBIbUd6IjujMmnOk9bY0WEUMcdm3Uotjdog==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.35.0.tgz", + "integrity": "sha512-3wkW03vXYMyWtTLxl9yrtkV+qxbnKFgfASdoGWhXzfLjycgT6o4/04eb3Gn71q9aXqRwH17ISVQbVswnRqMcmA==", "dependencies": { - "@sentry-internal/browser-utils": "8.33.1", - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry-internal/browser-utils": "8.35.0", + "@sentry/core": "8.35.0", + "@sentry/types": "8.35.0", + "@sentry/utils": "8.35.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.33.1.tgz", - "integrity": "sha512-nsxTFTPCT10Ty/v6+AiST3+yotGP1sUb8xqfKB9fPnS1hZHFryp0NnEls7xFjBsBbZPU1GpFkzrk/E6JFzixDQ==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.35.0.tgz", + "integrity": "sha512-TUrH6Piv19kvHIiRyIuapLdnuwxk/Un/l1WDCQfq7mK9p1Pac0FkQ7Uufjp6zY3lyhDDZQ8qvCS4ioCMibCwQg==", "dependencies": { - "@sentry-internal/replay": "8.33.1", - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry-internal/replay": "8.35.0", + "@sentry/core": "8.35.0", + "@sentry/types": "8.35.0", + "@sentry/utils": "8.35.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/browser": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.33.1.tgz", - "integrity": "sha512-c6zI/igexkLwZuGk+u8Rj26ChjxGgkhe6ZbKFsXCYaKAp5ep5X7HQRkkqgbxApiqlC0LduHdd/ymzh139JLg8w==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.35.0.tgz", + "integrity": "sha512-WHfI+NoZzpCsmIvtr6ChOe7yWPLQyMchPnVhY3Z4UeC70bkYNdKcoj/4XZbX3m0D8+71JAsm0mJ9s9OC3Ue6MQ==", "dependencies": { - "@sentry-internal/browser-utils": "8.33.1", - "@sentry-internal/feedback": "8.33.1", - "@sentry-internal/replay": "8.33.1", - "@sentry-internal/replay-canvas": "8.33.1", - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry-internal/browser-utils": "8.35.0", + "@sentry-internal/feedback": "8.35.0", + "@sentry-internal/replay": "8.35.0", + "@sentry-internal/replay-canvas": "8.35.0", + "@sentry/core": "8.35.0", + "@sentry/types": "8.35.0", + "@sentry/utils": "8.35.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/core": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.33.1.tgz", - "integrity": "sha512-3SS41suXLFzxL3OQvTMZ6q92ZapELVq2l2SoWlZopcamWhog2Ru0dp2vkunq97kFHb2TzKRTlFH4+4gbT8SJug==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.35.0.tgz", + "integrity": "sha512-Ci0Nmtw5ETWLqQJGY4dyF+iWh7PWKy6k303fCEoEmqj2czDrKJCp7yHBNV0XYbo00prj2ZTbCr6I7albYiyONA==", "dependencies": { - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry/types": "8.35.0", + "@sentry/utils": "8.35.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/react": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/react/-/react-8.33.1.tgz", - "integrity": "sha512-SsEX05xfcfOvo7/pK1UyeyTAYWH8iSIsXXlsjvnSRsbuJkjb0c+q6yiZpj3A2PRdbcx43nTVE1n0lSpgaqj2HA==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-8.35.0.tgz", + "integrity": "sha512-8Y+s4pE9hvT2TwSo5JS/Enw2cNFlwiLcJDNGCj/Hho+FePFYA59hbN06ouTHWARnO+swANHKZQj24Wp57p1/tg==", "dependencies": { - "@sentry/browser": "8.33.1", - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1", + "@sentry/browser": "8.35.0", + "@sentry/core": "8.35.0", + "@sentry/types": "8.35.0", + "@sentry/utils": "8.35.0", "hoist-non-react-statics": "^3.3.2" }, "engines": { @@ -924,28 +944,28 @@ } }, "node_modules/@sentry/types": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.33.1.tgz", - "integrity": "sha512-GjoAMvwtpIemoF/IiwZ7A60g4nQv3qwzR21GvJqDVUoKD0e8pv9OLX+HyXoUat4wEDGSuDUcUyUKD2G+od73QA==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.35.0.tgz", + "integrity": "sha512-AVEZjb16MlYPifiDDvJ19dPQyDn0jlrtC1PHs6ZKO+Rzyz+2EX2BRdszvanqArldexPoU1p5Bn2w81XZNXThBA==", "engines": { "node": ">=14.18" } }, "node_modules/@sentry/utils": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.33.1.tgz", - "integrity": "sha512-uzuYpiiJuFY3N4WNHMBWUQX5oNv2t/TbG0OHRp3Rr7yeu+HSfD542TIp9/gMZ+G0Cxd8AmVO3wkKIFbk0TL4Qg==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.35.0.tgz", + "integrity": "sha512-MdMb6+uXjqND7qIPWhulubpSeHzia6HtxeJa8jYI09OCvIcmNGPydv/Gx/LZBwosfMHrLdTWcFH7Y7aCxrq7cg==", "dependencies": { - "@sentry/types": "8.33.1" + "@sentry/types": "8.35.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@tanstack/history": { - "version": "1.57.6", - "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.57.6.tgz", - "integrity": "sha512-ppAJbnUaHdHmccVmplcd1ivX4GMPHxhStSquuuz0TSAEPEpz0iOVBur4iKfvIuMKm24c40nhvaEwZbKGVfbrGg==", + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.61.1.tgz", + "integrity": "sha512-2CqERleeqO3hkhJmyJm37tiL3LYgeOpmo8szqdjgtnnG0z7ZpvzkZz6HkfOr9Ca/ha7mhAiouSvLYuLkM37AMg==", "engines": { "node": ">=12" }, @@ -955,20 +975,20 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.56.2", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.56.2.tgz", - "integrity": "sha512-gor0RI3/R5rVV3gXfddh1MM+hgl0Z4G7tj6Xxpq6p2I03NGPaJ8dITY9Gz05zYYb/EJq9vPas/T4wn9EaDPd4Q==", + "version": "5.59.13", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.13.tgz", + "integrity": "sha512-Oou0bBu/P8+oYjXsJQ11j+gcpLAMpqW42UlokQYEz4dE7+hOtVO9rVuolJKgEccqzvyFzqX4/zZWY+R/v1wVsQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/react-query": { - "version": "5.56.2", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.56.2.tgz", - "integrity": "sha512-SR0GzHVo6yzhN72pnRhkEFRAHMsUo5ZPzAxfTMvUxFIDVS6W9LYUp6nXW3fcHVdg0ZJl8opSH85jqahvm6DSVg==", + "version": "5.59.15", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.15.tgz", + "integrity": "sha512-QbVlAkTI78wB4Mqgf2RDmgC0AOiJqer2c5k9STOOSXGv1S6ZkY37r/6UpE8DbQ2Du0ohsdoXgFNEyv+4eDoPEw==", "dependencies": { - "@tanstack/query-core": "5.56.2" + "@tanstack/query-core": "5.59.13" }, "funding": { "type": "github", @@ -979,12 +999,12 @@ } }, "node_modules/@tanstack/react-router": { - "version": "1.58.7", - "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.58.7.tgz", - "integrity": "sha512-iu4WtrhXz0YcJzPMlyP4jT3zfEKJH+dVVKViK8ayL1hWjP2n6A08kYE1hcT3YmuK2LmNmMsnGS+Tc7WAFsHgZQ==", + "version": "1.75.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.75.0.tgz", + "integrity": "sha512-iELqrMjlE/Y2JeOkvTfrPPKovrvtj1M+PTESfNfNv26Ja1efotcx0hEXiClmT7KYIlVBf0TowI5GUBNWGArm6A==", "dependencies": { - "@tanstack/history": "1.57.6", - "@tanstack/react-store": "^0.5.5", + "@tanstack/history": "1.61.1", + "@tanstack/react-store": "^0.5.6", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, @@ -996,7 +1016,7 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/router-generator": "1.58.1", + "@tanstack/router-generator": "1.74.2", "react": ">=18", "react-dom": ">=18" }, @@ -1007,8 +1027,9 @@ } }, "node_modules/@tanstack/react-store": { - "version": "0.5.5", - "license": "MIT", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.5.6.tgz", + "integrity": "sha512-SitIpS5jTj28DajjLpWbIX+YetmJL+6PRY0DKKiCGBKfYIqj3ryODQYF3jB3SNoR9ifUA/jFkqbJdBKFtWd+AQ==", "dependencies": { "@tanstack/store": "0.5.5", "use-sync-external-store": "^1.2.2" @@ -1045,12 +1066,12 @@ } }, "node_modules/@tanstack/router-generator": { - "version": "1.58.1", - "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.58.1.tgz", - "integrity": "sha512-oj/97KWi8EHFx/w07fAuXXyhWi5xgSMCfzbB9q42c1ZdLbv8wzBo4a6PO1fCi01tpKKHUopA8dSlGIOeJDhBAA==", + "version": "1.74.2", + "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.74.2.tgz", + "integrity": "sha512-S69fXvYcL+tQsO5Fe9ju/XVa/hZvk4pCaWbtoR2MNjIgR2RmjiFKOgXYeLRMNom/IpP/HAQmQ3m1DwU9jjSUKA==", "devOptional": true, "dependencies": { - "@tanstack/virtual-file-routes": "^1.56.0", + "@tanstack/virtual-file-routes": "^1.64.0", "prettier": "^3.3.3", "tsx": "^4.19.1", "zod": "^3.23.8" @@ -1532,21 +1553,21 @@ } }, "node_modules/@tanstack/router-plugin": { - "version": "1.58.4", - "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.58.4.tgz", - "integrity": "sha512-Ypoy+HrHwpv9A41bj7dpHhtLYavu7CU8WyuJnuFBY3SI5ZKWF7s/hMYUtVmEVwwT7fJCVQ8gcTkbfAag4uy/pA==", + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.76.0.tgz", + "integrity": "sha512-5JY1NeNbxi7jamTKTAWLyyC9t4Y9Ol+vFZB84h6F1K1BkxqeWQTCJuXMYCY3KawSd7xy2mVT/BgDyZ0AS5hKAA==", "dev": true, "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.6", - "@babel/parser": "^7.25.6", - "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/plugin-syntax-typescript": "^7.25.4", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.6", - "@babel/types": "^7.25.6", - "@tanstack/router-generator": "^1.58.1", - "@tanstack/virtual-file-routes": "^1.56.0", + "@babel/core": "^7.25.8", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.8", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/plugin-syntax-typescript": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.8", + "@tanstack/router-generator": "^1.74.2", + "@tanstack/virtual-file-routes": "^1.64.0", "@types/babel__core": "^7.20.5", "@types/babel__generator": "^7.6.8", "@types/babel__template": "^7.4.4", @@ -1582,16 +1603,17 @@ }, "node_modules/@tanstack/store": { "version": "0.5.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.5.5.tgz", + "integrity": "sha512-EOSrgdDAJExbvRZEQ/Xhh9iZchXpMN+ga1Bnk8Nmygzs8TfiE6hbzThF+Pr2G19uHL6+DTDTHhJ8VQiOd7l4tA==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/virtual-file-routes": { - "version": "1.56.0", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.56.0.tgz", - "integrity": "sha512-fBUj+lbSaw+VxoBN4J/WFE7dTx8x4XCTRAQvbiIyPJ8MY1KRVkdZV6cbLvg7MeDP6CxUcj6XNvWU6h0ic1Ipyg==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.64.0.tgz", + "integrity": "sha512-soW+gE9QTmMaqXM17r7y1p8NiQVIIECjdTaYla8BKL5Flj030m3KuxEQoiG1XgjtA0O7ayznFz2YvPcXIy3qDg==", "devOptional": true, "engines": { "node": ">=12" @@ -1675,9 +1697,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "version": "22.7.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.8.tgz", + "integrity": "sha512-a922jJy31vqR5sk+kAdIENJjHblqcZ4RmERviFsER4WJcEONqxKcjNOlk0q7OUfrF5sddT+vng070cdfMlrPLg==", "dev": true, "dependencies": { "undici-types": "~6.19.2" @@ -1689,9 +1711,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.8", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.8.tgz", - "integrity": "sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==", + "version": "18.3.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", + "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", "dev": true, "dependencies": { "@types/prop-types": "*", @@ -1699,24 +1721,25 @@ } }, "node_modules/@types/react-dom": { - "version": "18.3.0", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/react": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz", - "integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz", + "integrity": "sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.7.0", - "@typescript-eslint/type-utils": "8.7.0", - "@typescript-eslint/utils": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0", + "@typescript-eslint/scope-manager": "8.11.0", + "@typescript-eslint/type-utils": "8.11.0", + "@typescript-eslint/utils": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1740,15 +1763,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz", - "integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.11.0.tgz", + "integrity": "sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.7.0", - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/typescript-estree": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0", + "@typescript-eslint/scope-manager": "8.11.0", + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/typescript-estree": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0", "debug": "^4.3.4" }, "engines": { @@ -1768,13 +1791,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", - "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz", + "integrity": "sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0" + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1785,13 +1808,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz", - "integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.11.0.tgz", + "integrity": "sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.7.0", - "@typescript-eslint/utils": "8.7.0", + "@typescript-eslint/typescript-estree": "8.11.0", + "@typescript-eslint/utils": "8.11.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1809,9 +1832,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", - "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.11.0.tgz", + "integrity": "sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1822,13 +1845,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", - "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz", + "integrity": "sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0", + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1862,15 +1885,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", - "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.11.0.tgz", + "integrity": "sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.7.0", - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/typescript-estree": "8.7.0" + "@typescript-eslint/scope-manager": "8.11.0", + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/typescript-estree": "8.11.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1884,12 +1907,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", - "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz", + "integrity": "sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/types": "8.11.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -1906,13 +1929,14 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-react": { - "version": "4.3.1", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz", + "integrity": "sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/core": "^7.24.5", - "@babel/plugin-transform-react-jsx-self": "^7.24.5", - "@babel/plugin-transform-react-jsx-source": "^7.24.1", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, @@ -1967,8 +1991,9 @@ }, "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" }, @@ -2041,7 +2066,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.3", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -2057,10 +2084,9 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, @@ -2071,10 +2097,24 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/browserslist/node_modules/caniuse-lite": { - "version": "1.0.30001660", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", - "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", + "node_modules/buffer-builder": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", + "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001668", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz", + "integrity": "sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==", "dev": true, "funding": [ { @@ -2091,30 +2131,11 @@ } ] }, - "node_modules/browserslist/node_modules/electron-to-chromium": { - "version": "1.5.22", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.22.tgz", - "integrity": "sha512-tKYm5YHPU1djz0O+CGJ+oJIvimtsCcwR2Z9w7Skh08lUdyzXY5djods3q+z2JkWdb7tCcmM//eVavSRAiaPRNg==", - "dev": true - }, - "node_modules/buffer-builder": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", - "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", - "dev": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "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", @@ -2171,16 +2192,18 @@ }, "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/color-name": { "version": "1.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "node_modules/colorjs.io": { "version": "0.5.2", @@ -2283,18 +2306,26 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, + "node_modules/electron-to-chromium": { + "version": "1.5.38", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.38.tgz", + "integrity": "sha512-VbeVexmZ1IFh+5EfrYz1I0HTzHVIlJa112UEWhciPyeOcKJGeTv6N8WnG4wsQB81DGCaVEGhpSb6o6a8WYFXXg==", + "dev": true + }, "node_modules/escalade": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "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" } @@ -2365,9 +2396,9 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz", - "integrity": "sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg==", + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.13.tgz", + "integrity": "sha512-f1EppwrpJRWmqDTyvAyomFVDYRtrS7iTEqv3nokETnMiMzs2SSTmKRTACce4O2p4jYyowiSMvpdwC/RLcMFhuQ==", "dev": true, "peerDependencies": { "eslint": ">=7" @@ -2767,8 +2798,9 @@ }, "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" } @@ -2902,14 +2934,15 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, - "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { @@ -2989,8 +3022,9 @@ }, "node_modules/lru-cache": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^3.0.2" } @@ -3074,8 +3108,9 @@ }, "node_modules/node-releases": { "version": "2.0.18", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true }, "node_modules/normalize-path": { "version": "3.0.0", @@ -3189,12 +3224,12 @@ } }, "node_modules/playwright": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.0.tgz", - "integrity": "sha512-qPqFaMEHuY/ug8o0uteYJSRfMGFikhUysk8ZvAtfKmUK3kc/6oNl/y3EczF8OFGYIi/Ex2HspMfzYArk6+XQSA==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz", + "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==", "dev": true, "dependencies": { - "playwright-core": "1.48.0" + "playwright-core": "1.48.1" }, "bin": { "playwright": "cli.js" @@ -3207,9 +3242,9 @@ } }, "node_modules/playwright-core": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.0.tgz", - "integrity": "sha512-RBvzjM9rdpP7UUFrQzRwR8L/xR4HyC1QXMzGYTbf1vjw25/ya9NRAVnXi/0fvFopjebvyPzsmoK58xxeEOaVvA==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz", + "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -3467,9 +3502,9 @@ } }, "node_modules/sass-embedded": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.79.4.tgz", - "integrity": "sha512-3AATrtStMgxYjkit02/Ix8vx/P7qderYG6DHjmehfk5jiw53OaWVScmcGJSwp/d77kAkxDQ+Y0r+79VynGmrkw==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.80.3.tgz", + "integrity": "sha512-aTxTl4ToSAWg7ILFgAe+kMenj+zNlwHmHK/ZNPrOM8+HTef1Q6zuxolptYLijmHdZHKSMOkWYHgo5MMN6+GIyg==", "dev": true, "dependencies": { "@bufbuild/protobuf": "^2.0.0", @@ -3487,32 +3522,32 @@ "node": ">=16.0.0" }, "optionalDependencies": { - "sass-embedded-android-arm": "1.79.4", - "sass-embedded-android-arm64": "1.79.4", - "sass-embedded-android-ia32": "1.79.4", - "sass-embedded-android-riscv64": "1.79.4", - "sass-embedded-android-x64": "1.79.4", - "sass-embedded-darwin-arm64": "1.79.4", - "sass-embedded-darwin-x64": "1.79.4", - "sass-embedded-linux-arm": "1.79.4", - "sass-embedded-linux-arm64": "1.79.4", - "sass-embedded-linux-ia32": "1.79.4", - "sass-embedded-linux-musl-arm": "1.79.4", - "sass-embedded-linux-musl-arm64": "1.79.4", - "sass-embedded-linux-musl-ia32": "1.79.4", - "sass-embedded-linux-musl-riscv64": "1.79.4", - "sass-embedded-linux-musl-x64": "1.79.4", - "sass-embedded-linux-riscv64": "1.79.4", - "sass-embedded-linux-x64": "1.79.4", - "sass-embedded-win32-arm64": "1.79.4", - "sass-embedded-win32-ia32": "1.79.4", - "sass-embedded-win32-x64": "1.79.4" + "sass-embedded-android-arm": "1.80.3", + "sass-embedded-android-arm64": "1.80.3", + "sass-embedded-android-ia32": "1.80.3", + "sass-embedded-android-riscv64": "1.80.3", + "sass-embedded-android-x64": "1.80.3", + "sass-embedded-darwin-arm64": "1.80.3", + "sass-embedded-darwin-x64": "1.80.3", + "sass-embedded-linux-arm": "1.80.3", + "sass-embedded-linux-arm64": "1.80.3", + "sass-embedded-linux-ia32": "1.80.3", + "sass-embedded-linux-musl-arm": "1.80.3", + "sass-embedded-linux-musl-arm64": "1.80.3", + "sass-embedded-linux-musl-ia32": "1.80.3", + "sass-embedded-linux-musl-riscv64": "1.80.3", + "sass-embedded-linux-musl-x64": "1.80.3", + "sass-embedded-linux-riscv64": "1.80.3", + "sass-embedded-linux-x64": "1.80.3", + "sass-embedded-win32-arm64": "1.80.3", + "sass-embedded-win32-ia32": "1.80.3", + "sass-embedded-win32-x64": "1.80.3" } }, "node_modules/sass-embedded-android-arm": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.79.4.tgz", - "integrity": "sha512-YOVpDGDcwWUQvktpJhYo4zOkknDpdX6ALpaeHDTX6GBUvnZfx+Widh76v+QFUhiJQ/I/hndXg1jv/PKilOHRrw==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.80.3.tgz", + "integrity": "sha512-i87crav7sfShzY7AyUneXvs4SWdJ93QlYIpo/2OQPTJV5MjJF8wUp0o9NT8Oo6sUJ26kfgsb64FwqQh1wO5uBg==", "cpu": [ "arm" ], @@ -3526,9 +3561,9 @@ } }, "node_modules/sass-embedded-android-arm64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.79.4.tgz", - "integrity": "sha512-0JAZ8TtXYv9yI3Yasaq03xvo7DLJOmD+Exb30oJKxXcWTAV9TB0ZWKoIRsFxbCyPxyn7ouxkaCEXQtaTRKrmfw==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.80.3.tgz", + "integrity": "sha512-uaEKdi+PaFc1V87vj2eCUB8B2ThNvEYYu9Qs5sCtx1atEQDtvp/smHYlXOVrg2M4+g2YASkDBQewyk+auZtG0g==", "cpu": [ "arm64" ], @@ -3542,9 +3577,9 @@ } }, "node_modules/sass-embedded-android-ia32": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.79.4.tgz", - "integrity": "sha512-IjO3RoyvNN84ZyfAR5s/a8TIdNPfClb7CLGrswB3BN/NElYIJUJMVHD6+Y8W9QwBIZ8DrK1IdLFSTV8nn82xMA==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.80.3.tgz", + "integrity": "sha512-XCa4Se7vqWuV5tFLZuYWidPLUCeK7n1AgugircJl/9QPThCGZ2mSRF0Ipj3lv+Qw4GG9kkhCqJIrksTGbSFypw==", "cpu": [ "ia32" ], @@ -3558,9 +3593,9 @@ } }, "node_modules/sass-embedded-android-riscv64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.79.4.tgz", - "integrity": "sha512-uOT8nXmKxSwuIdcqvElVWBFcm/+YcIvmwfoKbpuuSOSxUe9eqFzxo+fk7ILhynzf6FBlvRUH5DcjGj+sXtCc3w==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.80.3.tgz", + "integrity": "sha512-Dn3hYh5rchfivnPrHoff2pWutuFYJRddzEXcjfb0JhgF7JmTA/6Dxaym0pqVpS1RmYDiAYnmoX5OeFtEkdVytA==", "cpu": [ "riscv64" ], @@ -3574,9 +3609,9 @@ } }, "node_modules/sass-embedded-android-x64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.79.4.tgz", - "integrity": "sha512-W2FQoj3Z2J2DirNs3xSBVvrhMuqLnsqvOPulxOkhL/074+faKOZZnPx2tZ5zsHbY97SonciiU0SV0mm98xI42w==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.80.3.tgz", + "integrity": "sha512-QWOTHKPznYJnrP3HrlFYnAQOZ/c2am4ctK1cFIMtjQNGaFra8z94LZSQzAd6eeu6mITKwQbJuff36RpICZpgHA==", "cpu": [ "x64" ], @@ -3590,9 +3625,9 @@ } }, "node_modules/sass-embedded-darwin-arm64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.79.4.tgz", - "integrity": "sha512-pcYtbN1VUAAcfgyHeX8ySndDWGjIvcq6rldduktPbGGuAlEWFDfnwjTbv0hS945ggdzZ6TFnaFlLEDr0SjKzBA==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.80.3.tgz", + "integrity": "sha512-NqJXHzZGqVOarr36X5MIv0UCQHYVhOFXGe7kDhNqMQCiNApkVydseB5TM1C2lVaiWy2JaseRD/dUNS/o2ICKXw==", "cpu": [ "arm64" ], @@ -3606,9 +3641,9 @@ } }, "node_modules/sass-embedded-darwin-x64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.79.4.tgz", - "integrity": "sha512-ir8CFTfc4JLx/qCP8LK1/3pWv35nRyAQkUK7lBIKM6hWzztt64gcno9rZIk4SpHr7Z/Bp1IYWWRS4ZT+4HmsbA==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.80.3.tgz", + "integrity": "sha512-6dmNn+oNxXE5uGThfAsHgz7Jg1oDhXHHQyPAnIIaMOM5dXv0D/nLmrlFbFajK0HtbzGaTVBTE6wkJwjASuP0Uw==", "cpu": [ "x64" ], @@ -3622,9 +3657,9 @@ } }, "node_modules/sass-embedded-linux-arm": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.79.4.tgz", - "integrity": "sha512-H/XEE3rY7c+tY0qDaELjPjC6VheAhBo1tPJQ6UHoBEf8xrbT/RT3dWiIS8grp9Vk54RCn05BEB/+POaljvvKGA==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.80.3.tgz", + "integrity": "sha512-nZ7Y8gZgr+/fYrbsX3L8BfIafWXGVBcc0gKLoujad+axlFGv1MetO17S3vzrOQ1wuhjvDLVxceA/jtcta1qxoA==", "cpu": [ "arm" ], @@ -3638,9 +3673,9 @@ } }, "node_modules/sass-embedded-linux-arm64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.79.4.tgz", - "integrity": "sha512-XIVn2mCuA422SR2kmKjF6jhjMs1Vrt1DbZ/ktSp+eR0sU4ugu2htg45GajiUFSKKRj7Sc+cBdThq1zPPsDLf1w==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.80.3.tgz", + "integrity": "sha512-a9IILen4I6oFFb5qMHOiFqIAoztPuvJ6VHNaFbktP8SUvH4FX63ZutR/qKisN9DoudzSXMZijv/aG/bTh0Kccw==", "cpu": [ "arm64" ], @@ -3654,9 +3689,9 @@ } }, "node_modules/sass-embedded-linux-ia32": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.79.4.tgz", - "integrity": "sha512-3nqZxV4nuUTb1ahLexVl4hsnx1KKwiGdHEf1xHWTZai6fYFMcwyNPrHySCQzFHqb5xiqSpPzzrKjuDhF6+guuQ==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.80.3.tgz", + "integrity": "sha512-yKy4N0L9WfGokpBMHOhxzaS3jyzrHUg1+5Idi6J88onwxfpEhqOgdMcoqgOqvryMPrmKN7kW5d3iNpUYOniPnw==", "cpu": [ "ia32" ], @@ -3670,9 +3705,9 @@ } }, "node_modules/sass-embedded-linux-musl-arm": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.79.4.tgz", - "integrity": "sha512-HnbU1DEiQdUayioNzxh2WlbTEgQRBPTgIIvof8J63QLmVItUqE7EkWYkSUy4RhO+8NsuN9wzGmGTzFBvTImU7g==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.80.3.tgz", + "integrity": "sha512-yB7iSoS/phNHKFsZRW0rTRwoCTtOBELG/UYpIa2qATWZsDASSjdBitGsKS3nEliweveuGIVlUqG2kUKaq9M39g==", "cpu": [ "arm" ], @@ -3686,9 +3721,9 @@ } }, "node_modules/sass-embedded-linux-musl-arm64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.79.4.tgz", - "integrity": "sha512-C6qX06waPEfDgOHR8jXoYxl0EtIXOyBDyyonrLO3StRjWjGx7XMQj2hA/KXSsV+Hr71fBOsaViosqWXPzTbEiQ==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.80.3.tgz", + "integrity": "sha512-mw4BPe42wlAwg6vgmGkg+MDDyXZBexvAWC+QigtfMjTVHuSAB527UVWhIyv4jAkKLp71mPowsXXsfa4UHzyBaA==", "cpu": [ "arm64" ], @@ -3702,9 +3737,9 @@ } }, "node_modules/sass-embedded-linux-musl-ia32": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.79.4.tgz", - "integrity": "sha512-y5b0fdOPWyhj4c+mc88GvQiC5onRH1V0iNaWNjsiZ+L4hHje6T98nDLrCJn0fz5GQnXjyLCLZduMWbfV0QjHGg==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.80.3.tgz", + "integrity": "sha512-eyg5L9IFisCYYMXEZ/56X8k8wdhpfK06/j9MFAINE9U4C5NxQXrVWmMTEqgyfpmca8hziBlvbRrjdquteyXWfw==", "cpu": [ "ia32" ], @@ -3718,9 +3753,9 @@ } }, "node_modules/sass-embedded-linux-musl-riscv64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.79.4.tgz", - "integrity": "sha512-G2M5ADMV9SqnkwpM0S+UzDz7xR2njCOhofku/sDMZABzAjQQWTsAykKoGmzlT98fTw2HbNhb6u74umf2WLhCfw==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.80.3.tgz", + "integrity": "sha512-0VThiW7Gwo5UNgKyETYID6F2prHvOCH8fQQKM0sS/JSbTu1poTwD35yEptVxBpiTvyWwxI7K5Cbn0gtxobaqzA==", "cpu": [ "riscv64" ], @@ -3734,9 +3769,9 @@ } }, "node_modules/sass-embedded-linux-musl-x64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.79.4.tgz", - "integrity": "sha512-kQm8dCU3DXf7DtUGWYPiPs03KJYKvFeiZJHhSx993DCM8D2b0wCXWky0S0Z46gf1sEur0SN4Lvnt1WczTqxIBw==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.80.3.tgz", + "integrity": "sha512-ALSKlhTQdNS0cayyaXD8huNd+DRjWgCjDqyjvwSgemfLL+wtmVCO8h9rGu1MCwR8GHP6ceZCT2fBmjfcGHk0DQ==", "cpu": [ "x64" ], @@ -3750,9 +3785,9 @@ } }, "node_modules/sass-embedded-linux-riscv64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.79.4.tgz", - "integrity": "sha512-GaTI/mXYWYSzG5wxtM4H2cozLpATyh+4l+rO9FFKOL8e1sUOLAzTeRdU2nSBYCuRqsxRuTZIwCXhSz9Q3NRuNA==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.80.3.tgz", + "integrity": "sha512-/1JvuQi137BNO7iTvNNraGYEt9mh3ch44cabJBTxLn3IZV5vNblENI+Hrj9J8/VWIsJumwPQGZSUrMbZcgB0tg==", "cpu": [ "riscv64" ], @@ -3766,9 +3801,9 @@ } }, "node_modules/sass-embedded-linux-x64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.79.4.tgz", - "integrity": "sha512-f9laGkqHgC01h99Qt4LsOV+OLMffjvUcTu14hYWqMS9QVX5a4ihMwpf1NoAtTUytb7cVF3rYY/NVGuXt6G3ppQ==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.80.3.tgz", + "integrity": "sha512-ISQUnl9oFA0PFPtgOpgotfKQ8guUBIYcTpkHEF9lQ4PyFIxkXppk5CwQ8l0VQcQaKhOD2HQAucoqM51U7FABqA==", "cpu": [ "x64" ], @@ -3782,9 +3817,9 @@ } }, "node_modules/sass-embedded-win32-arm64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.79.4.tgz", - "integrity": "sha512-cidBvtaA2cJ6dNlwQEa8qak+ezypurzKs0h0QAHLH324+j/6Jum7LCnQhZRPYJBFjHl+WYd7KwzPnJ2X5USWnQ==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.80.3.tgz", + "integrity": "sha512-RFT/OsWHVagPYa/9v+KfVM99QgzwzwnT2maapRfulEH39v0uPGOIFNXmnhaN3E5gNLIjIn3CTnR9KjTC145E8Q==", "cpu": [ "arm64" ], @@ -3798,9 +3833,9 @@ } }, "node_modules/sass-embedded-win32-ia32": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.79.4.tgz", - "integrity": "sha512-hexdmNTIZGTKNTzlMcdvEXzYuxOJcY89zqgsf45aQ2YMy4y2M8dTOxRI/Vz7p4iRxVp1Jow6LCtaLHrNI2Ordg==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.80.3.tgz", + "integrity": "sha512-Is0eeX+UlWW7yPfDqc2Z2n9ql2rkA1uDaAkbHWWx5APc8CKYtds1w4B3Tyoy6lHnopEifgzgsnp6QSyOHHzPBg==", "cpu": [ "ia32" ], @@ -3814,9 +3849,9 @@ } }, "node_modules/sass-embedded-win32-x64": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.79.4.tgz", - "integrity": "sha512-73yrpiWIbti6DkxhWURklkgSLYKfU9itDmvHxB+oYSb4vQveIApqTwSyTOuIUb/6Da/EsgEpdJ4Lbj4sLaMZWA==", + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.80.3.tgz", + "integrity": "sha512-wehVA0atPloc6NKof/ctpW0agM+k7kiBLIpQs3/mi9FAlmTjxNnvntBPZIbl8n7AAExiLEir+x/LHC0yGhTfkg==", "cpu": [ "x64" ], @@ -3862,8 +3897,9 @@ }, "node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -3919,8 +3955,9 @@ }, "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" }, @@ -4040,7 +4077,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -4056,10 +4095,9 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -4078,7 +4116,8 @@ }, "node_modules/use-sync-external-store": { "version": "1.2.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } @@ -4095,9 +4134,9 @@ "dev": true }, "node_modules/vite": { - "version": "5.4.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.7.tgz", - "integrity": "sha512-5l2zxqMEPVENgvzTuBpHer2awaetimj2BGkhBPdnwKbPNOlHsODU+oiazEZzLK7KhAnOrO+XGYJYn4ZlUhDtDQ==", + "version": "5.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz", + "integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==", "dev": true, "dependencies": { "esbuild": "^0.21.3", @@ -4610,8 +4649,9 @@ }, "node_modules/yallist": { "version": "3.1.1", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true }, "node_modules/yocto-queue": { "version": "0.1.0", @@ -4646,4 +4686,4 @@ "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 2f26c73..12161c7 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "git", "url": "https://github.com/codex-storage/codex-marketplace-ui" }, - "version": "0.0.3", + "version": "0.0.7", "type": "module", "scripts": { "dev": "vite --host 127.0.0.1 --port 5173", @@ -24,7 +24,7 @@ "React" ], "dependencies": { - "@codex-storage/marketplace-ui-components": "^0.0.22", + "@codex-storage/marketplace-ui-components": "^0.0.24", "@codex-storage/sdk-js": "^0.0.8", "@sentry/browser": "^8.32.0", "@sentry/react": "^8.31.0", diff --git a/src/components/CodexUrllSettings/CodexUrlSettings.tsx b/src/components/CodexUrllSettings/CodexUrlSettings.tsx index e0537f2..31bfe5d 100644 --- a/src/components/CodexUrllSettings/CodexUrlSettings.tsx +++ b/src/components/CodexUrllSettings/CodexUrlSettings.tsx @@ -1,4 +1,4 @@ -import { useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useState } from "react"; import { Button, Input, Toast } from "@codex-storage/marketplace-ui-components"; import { CodexSdk } from "../../sdk/codex"; @@ -6,31 +6,49 @@ import { CodexSdk } from "../../sdk/codex"; export function CodexUrlSettings() { const queryClient = useQueryClient(); const [url, setUrl] = useState(CodexSdk.url); + const [isInvalid, setIsInvalid] = useState(false); const [toast, setToast] = useState({ time: 0, message: "" }); + const { mutateAsync } = useMutation({ + mutationFn: (url: string) => CodexSdk.updateURL(url), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["spr"] }); + + setToast({ message: "Settings saved successfully.", time: Date.now() }); + }, + }); const onChange = (e: React.FormEvent) => { - const value = e.currentTarget.value; - if (value) { - setUrl(value); - } + const element = e.currentTarget; + const value = element.value; + + setUrl(value); + setIsInvalid(!element.checkValidity()); }; const onClick = () => { - CodexSdk.updateURL(url).then(() => { - queryClient.invalidateQueries(); - setToast({ message: "Settigns saved successfully.", time: Date.now() }); - }); + if (isInvalid === false) { + mutateAsync(url); + } }; return ( <> - - +
+ +
+ ); diff --git a/src/components/Debug/Debug.tsx b/src/components/Debug/Debug.tsx index fd875a4..339724b 100644 --- a/src/components/Debug/Debug.tsx +++ b/src/components/Debug/Debug.tsx @@ -1,15 +1,15 @@ import { useQuery } from "@tanstack/react-query"; import { CodexSdk } from "../../sdk/codex"; -import { Placeholder, Spinner } from "@codex-storage/marketplace-ui-components"; import { Promises } from "../../utils/promises"; -import { CircleX } from "lucide-react"; +import { Spinner } from "@codex-storage/marketplace-ui-components"; export function Debug() { - const { data, isPending, isError, error } = useQuery({ + const { data, isPending } = useQuery({ queryFn: () => CodexSdk.debug() .info() .then((s) => Promises.rejectOnError(s)), + queryKey: ["debug"], // No need to retry because if the connection to the node @@ -36,19 +36,10 @@ export function Debug() { ); } - if (isError) { - return ( - } - title="Something went wrong" - message={error.message}> - ); - } - return ( <>

Debug

-
{JSON.stringify(data, null, 2)}
+
{JSON.stringify(data, null, 2)}
); } diff --git a/src/components/Download/Download.css b/src/components/Download/Download.css new file mode 100644 index 0000000..7209c51 --- /dev/null +++ b/src/components/Download/Download.css @@ -0,0 +1,13 @@ +.download { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.download-inputContainer { + flex: 1; +} + +.download-input { + width: 100%; +} diff --git a/src/components/Download/Download.tsx b/src/components/Download/Download.tsx new file mode 100644 index 0000000..e6b19af --- /dev/null +++ b/src/components/Download/Download.tsx @@ -0,0 +1,28 @@ +import { Button, Input } from "@codex-storage/marketplace-ui-components"; +import "./Download.css"; +import { ChangeEvent, useState } from "react"; +import { CodexSdk } from "../../sdk/codex"; + +export function Download() { + const [cid, setCid] = useState(""); + const onDownload = () => { + const url = CodexSdk.url() + "/api/codex/v1/data/"; + window.open(url + cid + "/network/stream", "_target"); + }; + + const onCidChange = (e: ChangeEvent) => + setCid(e.currentTarget.value); + + return ( +
+
+ +
+ +
+ ); +} diff --git a/src/components/Peers/PeerCountryCell.tsx b/src/components/Peers/PeerCountryCell.tsx index 1edb332..0737655 100644 --- a/src/components/Peers/PeerCountryCell.tsx +++ b/src/components/Peers/PeerCountryCell.tsx @@ -1,8 +1,8 @@ import { Cell } from "@codex-storage/marketplace-ui-components"; import { PeerPin } from "./types"; -import { countriesCoordinates } from "./countries"; import { useQuery } from "@tanstack/react-query"; import "./PeerCountryCell.css"; +import { useEffect } from "react"; export type Props = { address: string; @@ -22,23 +22,12 @@ export function PeerCountryCell({ address, onPinAdd }: Props) { queryFn: () => { const [ip] = address.split(":"); - return fetch(import.meta.env.VITE_GEO_IP_URL + "/" + ip) - .then((res) => res.json()) - .then((json) => { - const coordinate = countriesCoordinates.find( - (c) => c.iso === json.country - ); - - if (coordinate) { - onPinAdd({ - lat: parseFloat(coordinate.lat), - lng: parseFloat(coordinate.lng), - }); - } - - return coordinate; - }); + return fetch(import.meta.env.VITE_GEO_IP_URL + "/json?ip=" + ip).then( + (res) => res.json() + ); }, + refetchOnMount: true, + queryKey: [address], // Enable only when the address exists @@ -56,13 +45,22 @@ export function PeerCountryCell({ address, onPinAdd }: Props) { refetchOnWindowFocus: false, }); + useEffect(() => { + if (data) { + onPinAdd({ + lat: data.latitude, + lng: data.longitude, + }); + } + }, [data]); + return (
{data ? ( <> - {!!data && getFlagEmoji(data.iso)} - {data?.name} + {!!data && getFlagEmoji(data.country_iso)} + {data?.country} ) : ( {address} diff --git a/src/components/Peers/countries.ts b/src/components/Peers/countries.ts deleted file mode 100644 index 3d001d8..0000000 --- a/src/components/Peers/countries.ts +++ /dev/null @@ -1,1563 +0,0 @@ -export const countriesCoordinates = [ - { - "iso": "AF", - "lat": "33", - "lng": "65", - "name": "Afghanistan" - }, - { - "iso": "AX", - "lat": "60.116667", - "lng": "19.9", - "name": "Åland Islands" - }, - { - "iso": "AL", - "lat": "41", - "lng": "20", - "name": "Albania" - }, - { - "iso": "DZ", - "lat": "28", - "lng": "3", - "name": "Algeria" - }, - { - "iso": "AS", - "lat": "-14.3333", - "lng": "-170", - "name": "American Samoa" - }, - { - "iso": "AD", - "lat": "42.5", - "lng": "1.6", - "name": "Andorra" - }, - { - "iso": "AO", - "lat": "-12.5", - "lng": "18.5", - "name": "Angola" - }, - { - "iso": "AI", - "lat": "18.25", - "lng": "-63.1667", - "name": "Anguilla" - }, - { - "iso": "AQ", - "lat": "-90", - "lng": "0", - "name": "Antarctica" - }, - { - "iso": "AG", - "lat": "17.05", - "lng": "-61.8", - "name": "Antigua and Barbuda" - }, - { - "iso": "AR", - "lat": "-34", - "lng": "-64", - "name": "Argentina" - }, - { - "iso": "AM", - "lat": "40", - "lng": "45", - "name": "Armenia" - }, - { - "iso": "AW", - "lat": "12.5", - "lng": "-69.9667", - "name": "Aruba" - }, - { - "iso": "AU", - "lat": "-27", - "lng": "133", - "name": "Australia" - }, - { - "iso": "AT", - "lat": "47.3333", - "lng": "13.3333", - "name": "Austria" - }, - { - "iso": "AZ", - "lat": "40.5", - "lng": "47.5", - "name": "Azerbaijan" - }, - { - "iso": "BS", - "lat": "24.25", - "lng": "-76", - "name": "Bahamas" - }, - { - "iso": "BH", - "lat": "26", - "lng": "50.55", - "name": "Bahrain" - }, - { - "iso": "BD", - "lat": "24", - "lng": "90", - "name": "Bangladesh" - }, - { - "iso": "BB", - "lat": "13.1667", - "lng": "-59.5333", - "name": "Barbados" - }, - { - "iso": "BY", - "lat": "53", - "lng": "28", - "name": "Belarus" - }, - { - "iso": "BE", - "lat": "50.8333", - "lng": "4", - "name": "Belgium" - }, - { - "iso": "BZ", - "lat": "17.25", - "lng": "-88.75", - "name": "Belize" - }, - { - "iso": "BJ", - "lat": "9.5", - "lng": "2.25", - "name": "Benin" - }, - { - "iso": "BM", - "lat": "32.3333", - "lng": "-64.75", - "name": "Bermuda" - }, - { - "iso": "BT", - "lat": "27.5", - "lng": "90.5", - "name": "Bhutan" - }, - { - "iso": "Plurinational State of", - "lat": "68", - "lng": "-17" - }, - { - "iso": "BO", - "lat": "-17", - "lng": "-65", - "name": "Bolivia, Plurinational State of" - }, - { - "iso": "Sint Eustatius and Saba", - "lat": "535", - "lng": "12.183333" - }, - { - "iso": "BA", - "lat": "44", - "lng": "18", - "name": "Bosnia and Herzegovina" - }, - { - "iso": "BW", - "lat": "-22", - "lng": "24", - "name": "Botswana" - }, - { - "iso": "BV", - "lat": "-54.4333", - "lng": "3.4", - "name": "Bouvet Island" - }, - { - "iso": "BR", - "lat": "-10", - "lng": "-55", - "name": "Brazil" - }, - { - "iso": "IO", - "lat": "-6", - "lng": "71.5", - "name": "British Indian Ocean Territory" - }, - { - "iso": "BN", - "lat": "4.5", - "lng": "114.6667", - "name": "Brunei Darussalam" - }, - { - "iso": "BN", - "lat": "4.5", - "lng": "114.6667", - "name": "Brunei Darussalam" - }, - { - "iso": "BG", - "lat": "43", - "lng": "25", - "name": "Bulgaria" - }, - { - "iso": "BF", - "lat": "13", - "lng": "-2", - "name": "Burkina Faso" - }, - { - "iso": "MM", - "lat": "22", - "lng": "98", - "name": "Myanmar" - }, - { - "iso": "BI", - "lat": "-3.5", - "lng": "30", - "name": "Burundi" - }, - { - "iso": "KH", - "lat": "13", - "lng": "105", - "name": "Cambodia" - }, - { - "iso": "CM", - "lat": "6", - "lng": "12", - "name": "Cameroon" - }, - { - "iso": "CA", - "lat": "60", - "lng": "-95", - "name": "Canada" - }, - { - "iso": "CV", - "lat": "16", - "lng": "-24", - "name": "Cape Verde" - }, - { - "iso": "KY", - "lat": "19.5", - "lng": "-80.5", - "name": "Cayman Islands" - }, - { - "iso": "CF", - "lat": "7", - "lng": "21", - "name": "Central African Republic" - }, - { - "iso": "TD", - "lat": "15", - "lng": "19", - "name": "Chad" - }, - { - "iso": "CL", - "lat": "-30", - "lng": "-71", - "name": "Chile" - }, - { - "iso": "CN", - "lat": "35", - "lng": "105", - "name": "China" - }, - { - "iso": "CX", - "lat": "-10.5", - "lng": "105.6667", - "name": "Christmas Island" - }, - { - "iso": "CC", - "lat": "-12.5", - "lng": "96.8333", - "name": "Cocos (Keeling) Islands" - }, - { - "iso": "CO", - "lat": "4", - "lng": "-72", - "name": "Colombia" - }, - { - "iso": "KM", - "lat": "-12.1667", - "lng": "44.25", - "name": "Comoros" - }, - { - "iso": "the Democratic Republic of the", - "lat": "180", - "lng": "0" - }, - { - "iso": "CG", - "lat": "-1", - "lng": "15", - "name": "Congo" - }, - { - "iso": "CK", - "lat": "-21.2333", - "lng": "-159.7667", - "name": "Cook Islands" - }, - { - "iso": "CR", - "lat": "10", - "lng": "-84", - "name": "Costa Rica" - }, - { - "iso": "CI", - "lat": "8", - "lng": "-5", - "name": "Côte d'Ivoire" - }, - { - "iso": "HR", - "lat": "45.1667", - "lng": "15.5", - "name": "Croatia" - }, - { - "iso": "CU", - "lat": "21.5", - "lng": "-80", - "name": "Cuba" - }, - { - "iso": "CW", - "lat": "12.166667", - "lng": "-68.966667", - "name": "Curaçao" - }, - { - "iso": "CY", - "lat": "35", - "lng": "33", - "name": "Cyprus" - }, - { - "iso": "CZ", - "lat": "49.75", - "lng": "15.5", - "name": "Czech Republic" - }, - { - "iso": "DK", - "lat": "56", - "lng": "10", - "name": "Denmark" - }, - { - "iso": "DJ", - "lat": "11.5", - "lng": "43", - "name": "Djibouti" - }, - { - "iso": "DM", - "lat": "15.4167", - "lng": "-61.3333", - "name": "Dominica" - }, - { - "iso": "DO", - "lat": "19", - "lng": "-70.6667", - "name": "Dominican Republic" - }, - { - "iso": "EC", - "lat": "-2", - "lng": "-77.5", - "name": "Ecuador" - }, - { - "iso": "EG", - "lat": "27", - "lng": "30", - "name": "Egypt" - }, - { - "iso": "SV", - "lat": "13.8333", - "lng": "-88.9167", - "name": "El Salvador" - }, - { - "iso": "GQ", - "lat": "2", - "lng": "10", - "name": "Equatorial Guinea" - }, - { - "iso": "ER", - "lat": "15", - "lng": "39", - "name": "Eritrea" - }, - { - "iso": "EE", - "lat": "59", - "lng": "26", - "name": "Estonia" - }, - { - "iso": "ET", - "lat": "8", - "lng": "38", - "name": "Ethiopia" - }, - { - "iso": "FK", - "lat": "-51.75", - "lng": "-59", - "name": "Falkland Islands (Malvinas)" - }, - { - "iso": "FO", - "lat": "62", - "lng": "-7", - "name": "Faroe Islands" - }, - { - "iso": "FJ", - "lat": "-18", - "lng": "175", - "name": "Fiji" - }, - { - "iso": "FI", - "lat": "64", - "lng": "26", - "name": "Finland" - }, - { - "iso": "FR", - "lat": "46", - "lng": "2", - "name": "France" - }, - { - "iso": "GF", - "lat": "4", - "lng": "-53", - "name": "French Guiana" - }, - { - "iso": "PF", - "lat": "-15", - "lng": "-140", - "name": "French Polynesia" - }, - { - "iso": "TF", - "lat": "-43", - "lng": "67", - "name": "French Southern Territories" - }, - { - "iso": "GA", - "lat": "-1", - "lng": "11.75", - "name": "Gabon" - }, - { - "iso": "GM", - "lat": "13.4667", - "lng": "-16.5667", - "name": "Gambia" - }, - { - "iso": "GE", - "lat": "42", - "lng": "43.5", - "name": "Georgia" - }, - { - "iso": "DE", - "lat": "51", - "lng": "9", - "name": "Germany" - }, - { - "iso": "GH", - "lat": "8", - "lng": "-2", - "name": "Ghana" - }, - { - "iso": "GI", - "lat": "36.1833", - "lng": "-5.3667", - "name": "Gibraltar" - }, - { - "iso": "GR", - "lat": "39", - "lng": "22", - "name": "Greece" - }, - { - "iso": "GL", - "lat": "72", - "lng": "-40", - "name": "Greenland" - }, - { - "iso": "GD", - "lat": "12.1167", - "lng": "-61.6667", - "name": "Grenada" - }, - { - "iso": "GP", - "lat": "16.25", - "lng": "-61.5833", - "name": "Guadeloupe" - }, - { - "iso": "GU", - "lat": "13.4667", - "lng": "144.7833", - "name": "Guam" - }, - { - "iso": "GT", - "lat": "15.5", - "lng": "-90.25", - "name": "Guatemala" - }, - { - "iso": "GG", - "lat": "49.5", - "lng": "-2.56", - "name": "Guernsey" - }, - { - "iso": "GW", - "lat": "12", - "lng": "-15", - "name": "Guinea-Bissau" - }, - { - "iso": "GN", - "lat": "11", - "lng": "-10", - "name": "Guinea" - }, - { - "iso": "GY", - "lat": "5", - "lng": "-59", - "name": "Guyana" - }, - { - "iso": "HT", - "lat": "19", - "lng": "-72.4167", - "name": "Haiti" - }, - { - "iso": "HM", - "lat": "-53.1", - "lng": "72.5167", - "name": "Heard Island and McDonald Islands" - }, - { - "iso": "VA", - "lat": "41.9", - "lng": "12.45", - "name": "Holy See (Vatican City State)" - }, - { - "iso": "HN", - "lat": "15", - "lng": "-86.5", - "name": "Honduras" - }, - { - "iso": "HK", - "lat": "22.25", - "lng": "114.1667", - "name": "Hong Kong" - }, - { - "iso": "HU", - "lat": "47", - "lng": "20", - "name": "Hungary" - }, - { - "iso": "IS", - "lat": "65", - "lng": "-18", - "name": "Iceland" - }, - { - "iso": "IN", - "lat": "20", - "lng": "77", - "name": "India" - }, - { - "iso": "ID", - "lat": "-5", - "lng": "120", - "name": "Indonesia" - }, - { - "iso": "Islamic Republic of", - "lat": "364", - "lng": "32" - }, - { - "iso": "IQ", - "lat": "33", - "lng": "44", - "name": "Iraq" - }, - { - "iso": "IE", - "lat": "53", - "lng": "-8", - "name": "Ireland" - }, - { - "iso": "IM", - "lat": "54.23", - "lng": "-4.55", - "name": "Isle of Man" - }, - { - "iso": "IL", - "lat": "31.5", - "lng": "34.75", - "name": "Israel" - }, - { - "iso": "IT", - "lat": "42.8333", - "lng": "12.8333", - "name": "Italy" - }, - { - "iso": "CI", - "lat": "8", - "lng": "-5", - "name": "Côte d'Ivoire" - }, - { - "iso": "JM", - "lat": "18.25", - "lng": "-77.5", - "name": "Jamaica" - }, - { - "iso": "JP", - "lat": "36", - "lng": "138", - "name": "Japan" - }, - { - "iso": "JE", - "lat": "49.21", - "lng": "-2.13", - "name": "Jersey" - }, - { - "iso": "JO", - "lat": "31", - "lng": "36", - "name": "Jordan" - }, - { - "iso": "KZ", - "lat": "48", - "lng": "68", - "name": "Kazakhstan" - }, - { - "iso": "KE", - "lat": "1", - "lng": "38", - "name": "Kenya" - }, - { - "iso": "KI", - "lat": "1.4167", - "lng": "173", - "name": "Kiribati" - }, - { - "iso": "Democratic People's Republic of", - "lat": "408", - "lng": "40" - }, - { - "iso": "Republic of", - "lat": "410", - "lng": "37" - }, - { - "iso": "XK", - "lat": "42.583333", - "lng": "21" - }, - { - "iso": "KW", - "lat": "29.3375", - "lng": "47.6581", - "name": "Kuwait" - }, - { - "iso": "KG", - "lat": "41", - "lng": "75", - "name": "Kyrgyzstan" - }, - { - "iso": "LA", - "lat": "18", - "lng": "105", - "name": "Lao People's Democratic Republic" - }, - { - "iso": "LV", - "lat": "57", - "lng": "25", - "name": "Latvia" - }, - { - "iso": "LB", - "lat": "33.8333", - "lng": "35.8333", - "name": "Lebanon" - }, - { - "iso": "LS", - "lat": "-29.5", - "lng": "28.5", - "name": "Lesotho" - }, - { - "iso": "LR", - "lat": "6.5", - "lng": "-9.5", - "name": "Liberia" - }, - { - "iso": "LY", - "lat": "25", - "lng": "17", - "name": "Libya" - }, - { - "iso": "LY", - "lat": "25", - "lng": "17", - "name": "Libya" - }, - { - "iso": "LI", - "lat": "47.1667", - "lng": "9.5333", - "name": "Liechtenstein" - }, - { - "iso": "LT", - "lat": "56", - "lng": "24", - "name": "Lithuania" - }, - { - "iso": "LU", - "lat": "49.75", - "lng": "6.1667", - "name": "Luxembourg" - }, - { - "iso": "MO", - "lat": "22.1667", - "lng": "113.55", - "name": "Macao" - }, - { - "iso": "the former Yugoslav Republic of", - "lat": "807", - "lng": "41.8333" - }, - { - "iso": "MG", - "lat": "-20", - "lng": "47", - "name": "Madagascar" - }, - { - "iso": "MW", - "lat": "-13.5", - "lng": "34", - "name": "Malawi" - }, - { - "iso": "MY", - "lat": "2.5", - "lng": "112.5", - "name": "Malaysia" - }, - { - "iso": "MV", - "lat": "3.25", - "lng": "73", - "name": "Maldives" - }, - { - "iso": "ML", - "lat": "17", - "lng": "-4", - "name": "Mali" - }, - { - "iso": "MT", - "lat": "35.8333", - "lng": "14.5833", - "name": "Malta" - }, - { - "iso": "MH", - "lat": "9", - "lng": "168", - "name": "Marshall Islands" - }, - { - "iso": "MQ", - "lat": "14.6667", - "lng": "-61", - "name": "Martinique" - }, - { - "iso": "MR", - "lat": "20", - "lng": "-12", - "name": "Mauritania" - }, - { - "iso": "MU", - "lat": "-20.2833", - "lng": "57.55", - "name": "Mauritius" - }, - { - "iso": "YT", - "lat": "-12.8333", - "lng": "45.1667", - "name": "Mayotte" - }, - { - "iso": "MX", - "lat": "23", - "lng": "-102", - "name": "Mexico" - }, - { - "iso": "Federated States of", - "lat": "583", - "lng": "6.9167" - }, - { - "iso": "Republic of", - "lat": "498", - "lng": "47" - }, - { - "iso": "MC", - "lat": "43.7333", - "lng": "7.4", - "name": "Monaco" - }, - { - "iso": "MN", - "lat": "46", - "lng": "105", - "name": "Mongolia" - }, - { - "iso": "ME", - "lat": "42", - "lng": "19", - "name": "Montenegro" - }, - { - "iso": "MS", - "lat": "16.75", - "lng": "-62.2", - "name": "Montserrat" - }, - { - "iso": "MA", - "lat": "32", - "lng": "-5", - "name": "Morocco" - }, - { - "iso": "MD", - "lat": "46.9804", - "lng": "28.3897", - "name": "Moldova" - }, - { - "iso": "MZ", - "lat": "-18.25", - "lng": "35", - "name": "Mozambique" - }, - { - "iso": "MM", - "lat": "22", - "lng": "98", - "name": "Myanmar" - }, - { - "iso": "NA", - "lat": "-22", - "lng": "17", - "name": "Namibia" - }, - { - "iso": "NR", - "lat": "-0.5333", - "lng": "166.9167", - "name": "Nauru" - }, - { - "iso": "NP", - "lat": "28", - "lng": "84", - "name": "Nepal" - }, - { - "iso": "AN", - "lat": "12.25", - "lng": "-68.75" - }, - { - "iso": "NL", - "lat": "52.5", - "lng": "5.75", - "name": "Netherlands" - }, - { - "iso": "NC", - "lat": "-21.5", - "lng": "165.5", - "name": "New Caledonia" - }, - { - "iso": "NZ", - "lat": "-41", - "lng": "174", - "name": "New Zealand" - }, - { - "iso": "NI", - "lat": "13", - "lng": "-85", - "name": "Nicaragua" - }, - { - "iso": "NE", - "lat": "16", - "lng": "8", - "name": "Niger" - }, - { - "iso": "NG", - "lat": "10", - "lng": "8", - "name": "Nigeria" - }, - { - "iso": "NU", - "lat": "-19.0333", - "lng": "-169.8667", - "name": "Niue" - }, - { - "iso": "NF", - "lat": "-29.0333", - "lng": "167.95", - "name": "Norfolk Island" - }, - { - "iso": "MP", - "lat": "15.2", - "lng": "145.75", - "name": "Northern Mariana Islands" - }, - { - "iso": "NO", - "lat": "62", - "lng": "10", - "name": "Norway" - }, - { - "iso": "OM", - "lat": "21", - "lng": "57", - "name": "Oman" - }, - { - "iso": "PK", - "lat": "30", - "lng": "70", - "name": "Pakistan" - }, - { - "iso": "PW", - "lat": "7.5", - "lng": "134.5", - "name": "Palau" - }, - { - "iso": "Occupied", - "lat": "275", - "lng": "32" - }, - { - "iso": "PA", - "lat": "9", - "lng": "-80", - "name": "Panama" - }, - { - "iso": "PG", - "lat": "-6", - "lng": "147", - "name": "Papua New Guinea" - }, - { - "iso": "PY", - "lat": "-23", - "lng": "-58", - "name": "Paraguay" - }, - { - "iso": "PE", - "lat": "-10", - "lng": "-76", - "name": "Peru" - }, - { - "iso": "PH", - "lat": "13", - "lng": "122", - "name": "Philippines" - }, - { - "iso": "PN", - "lat": "-24.7", - "lng": "-127.4", - "name": "Pitcairn" - }, - { - "iso": "PL", - "lat": "52", - "lng": "20", - "name": "Poland" - }, - { - "iso": "PT", - "lat": "39.5", - "lng": "-8", - "name": "Portugal" - }, - { - "iso": "PR", - "lat": "18.25", - "lng": "-66.5", - "name": "Puerto Rico" - }, - { - "iso": "QA", - "lat": "25.5", - "lng": "51.25", - "name": "Qatar" - }, - { - "iso": "RE", - "lat": "-21.1", - "lng": "55.6", - "name": "Réunion" - }, - { - "iso": "RO", - "lat": "46", - "lng": "25", - "name": "Romania" - }, - { - "iso": "RU", - "lat": "60", - "lng": "100", - "name": "Russian Federation" - }, - { - "iso": "RU", - "lat": "60", - "lng": "100", - "name": "Russian Federation" - }, - { - "iso": "RW", - "lat": "-2", - "lng": "30", - "name": "Rwanda" - }, - { - "iso": "BL", - "lat": "17.897728", - "lng": "-62.834244", - "name": "Saint Barthélemy" - }, - { - "iso": "Ascension and Tristan da Cunha", - "lat": "654", - "lng": "-15.9333" - }, - { - "iso": "KN", - "lat": "17.3333", - "lng": "-62.75", - "name": "Saint Kitts and Nevis" - }, - { - "iso": "LC", - "lat": "13.8833", - "lng": "-61.1333", - "name": "Saint Lucia" - }, - { - "iso": "MF", - "lat": "18.075278", - "lng": "-63.06", - "name": "Saint Martin (French part)" - }, - { - "iso": "PM", - "lat": "46.8333", - "lng": "-56.3333", - "name": "Saint Pierre and Miquelon" - }, - { - "iso": "VC", - "lat": "13.25", - "lng": "-61.2", - "name": "Saint Vincent and the Grenadines" - }, - { - "iso": "VC", - "lat": "13.25", - "lng": "-61.2", - "name": "Saint Vincent and the Grenadines" - }, - { - "iso": "WS", - "lat": "-13.5833", - "lng": "-172.3333", - "name": "Samoa" - }, - { - "iso": "SM", - "lat": "43.7667", - "lng": "12.4167", - "name": "San Marino" - }, - { - "iso": "ST", - "lat": "1", - "lng": "7", - "name": "Sao Tome and Principe" - }, - { - "iso": "SA", - "lat": "25", - "lng": "45", - "name": "Saudi Arabia" - }, - { - "iso": "SN", - "lat": "14", - "lng": "-14", - "name": "Senegal" - }, - { - "iso": "RS", - "lat": "44", - "lng": "21", - "name": "Serbia" - }, - { - "iso": "SC", - "lat": "-4.5833", - "lng": "55.6667", - "name": "Seychelles" - }, - { - "iso": "SL", - "lat": "8.5", - "lng": "-11.5", - "name": "Sierra Leone" - }, - { - "iso": "SG", - "lat": "1.3667", - "lng": "103.8", - "name": "Singapore" - }, - { - "iso": "SX", - "lat": "18.033333", - "lng": "-63.05", - "name": "Sint Maarten (Dutch part)" - }, - { - "iso": "SK", - "lat": "48.6667", - "lng": "19.5", - "name": "Slovakia" - }, - { - "iso": "SI", - "lat": "46", - "lng": "15", - "name": "Slovenia" - }, - { - "iso": "SB", - "lat": "-8", - "lng": "159", - "name": "Solomon Islands" - }, - { - "iso": "SO", - "lat": "10", - "lng": "49", - "name": "Somalia" - }, - { - "iso": "ZA", - "lat": "-29", - "lng": "24", - "name": "South Africa" - }, - { - "iso": "GS", - "lat": "-54.5", - "lng": "-37", - "name": "South Georgia and the South Sandwich Islands" - }, - { - "iso": "KR", - "lat": "37", - "lng": "127.5", - "name": "Korea, Republic of" - }, - { - "iso": "SS", - "lat": "8", - "lng": "30", - "name": "South Sudan" - }, - { - "iso": "ES", - "lat": "40", - "lng": "-4", - "name": "Spain" - }, - { - "iso": "LK", - "lat": "7", - "lng": "81", - "name": "Sri Lanka" - }, - { - "iso": "VC", - "lat": "13.25", - "lng": "-61.2", - "name": "Saint Vincent and the Grenadines" - }, - { - "iso": "SD", - "lat": "15", - "lng": "30", - "name": "Sudan" - }, - { - "iso": "SR", - "lat": "4", - "lng": "-56", - "name": "Suriname" - }, - { - "iso": "SJ", - "lat": "78", - "lng": "20", - "name": "Svalbard and Jan Mayen" - }, - { - "iso": "SZ", - "lat": "-26.5", - "lng": "31.5", - "name": "Swaziland" - }, - { - "iso": "SE", - "lat": "62", - "lng": "15", - "name": "Sweden" - }, - { - "iso": "CH", - "lat": "47", - "lng": "8", - "name": "Switzerland" - }, - { - "iso": "SY", - "lat": "35", - "lng": "38", - "name": "Syrian Arab Republic" - }, - { - "iso": "TW", - "lat": "23.5", - "lng": "121", - "name": "Taiwan, Province of China" - }, - { - "iso": "TJ", - "lat": "39", - "lng": "71", - "name": "Tajikistan" - }, - { - "iso": "United Republic of", - "lat": "834", - "lng": "-6" - }, - { - "iso": "TH", - "lat": "15", - "lng": "100", - "name": "Thailand" - }, - { - "iso": "TL", - "lat": "-8.55", - "lng": "125.5167", - "name": "Timor-Leste" - }, - { - "iso": "TG", - "lat": "8", - "lng": "1.1667", - "name": "Togo" - }, - { - "iso": "TK", - "lat": "-9", - "lng": "-172", - "name": "Tokelau" - }, - { - "iso": "TO", - "lat": "-20", - "lng": "-175", - "name": "Tonga" - }, - { - "iso": "TT", - "lat": "11", - "lng": "-61", - "name": "Trinidad and Tobago" - }, - { - "iso": "TN", - "lat": "34", - "lng": "9", - "name": "Tunisia" - }, - { - "iso": "TR", - "lat": "39", - "lng": "35", - "name": "Turkey" - }, - { - "iso": "TM", - "lat": "40", - "lng": "60", - "name": "Turkmenistan" - }, - { - "iso": "TC", - "lat": "21.75", - "lng": "-71.5833", - "name": "Turks and Caicos Islands" - }, - { - "iso": "TV", - "lat": "-8", - "lng": "178", - "name": "Tuvalu" - }, - { - "iso": "UG", - "lat": "1", - "lng": "32", - "name": "Uganda" - }, - { - "iso": "UA", - "lat": "49", - "lng": "32", - "name": "Ukraine" - }, - { - "iso": "AE", - "lat": "24", - "lng": "54", - "name": "United Arab Emirates" - }, - { - "iso": "GB", - "lat": "54", - "lng": "-2", - "name": "United Kingdom" - }, - { - "iso": "UM", - "lat": "19.2833", - "lng": "166.6", - "name": "United States Minor Outlying Islands" - }, - { - "iso": "US", - "lat": "38", - "lng": "-97", - "name": "United States" - }, - { - "iso": "UY", - "lat": "-33", - "lng": "-56", - "name": "Uruguay" - }, - { - "iso": "UZ", - "lat": "41", - "lng": "64", - "name": "Uzbekistan" - }, - { - "iso": "VU", - "lat": "-16", - "lng": "167", - "name": "Vanuatu" - }, - { - "iso": "Bolivarian Republic of", - "lat": "862", - "lng": "8" - }, - { - "iso": "VE", - "lat": "8", - "lng": "-66", - "name": "Venezuela, Bolivarian Republic of" - }, - { - "iso": "VN", - "lat": "16", - "lng": "106", - "name": "Viet Nam" - }, - { - "iso": "VN", - "lat": "16", - "lng": "106", - "name": "Viet Nam" - }, - { - "iso": "British", - "lat": "92", - "lng": "18.5" - }, - { - "iso": "U.S.", - "lat": "850", - "lng": "18.3333" - }, - { - "iso": "WF", - "lat": "-13.3", - "lng": "-176.2", - "name": "Wallis and Futuna" - }, - { - "iso": "EH", - "lat": "24.5", - "lng": "-13", - "name": "Western Sahara" - }, - { - "iso": "YE", - "lat": "15", - "lng": "48", - "name": "Yemen" - }, - { - "iso": "ZM", - "lat": "-15", - "lng": "30", - "name": "Zambia" - }, - { - "iso": "ZW", - "lat": "-20", - "lng": "30", - "name": "Zimbabwe" - } -] \ No newline at end of file diff --git a/src/components/Welcome/Welcome.css b/src/components/Welcome/Welcome.css index 491b9d8..3530439 100644 --- a/src/components/Welcome/Welcome.css +++ b/src/components/Welcome/Welcome.css @@ -6,6 +6,7 @@ display: flex; align-items: flex-start; flex-direction: column; + flex: 1; } .welcome-disclaimer { diff --git a/src/components/Welcome/Welcome.tsx b/src/components/Welcome/Welcome.tsx index e376ff1..0c31579 100644 --- a/src/components/Welcome/Welcome.tsx +++ b/src/components/Welcome/Welcome.tsx @@ -1,4 +1,4 @@ -import { Alert, SimpleText } from "@codex-storage/marketplace-ui-components"; +import { SimpleText } from "@codex-storage/marketplace-ui-components"; import "./Welcome.css"; import { Link } from "@tanstack/react-router"; import { ChevronRight } from "lucide-react"; @@ -14,13 +14,6 @@ export function Welcome() { explore its features. Your feedback is invaluable as we continue to improve! - - The website and the content herein is not intended for public use and - is for informational and demonstration purposes only. -
diff --git a/src/main.tsx b/src/main.tsx index fa8679e..3e88972 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -15,7 +15,7 @@ import * as Sentry from "@sentry/react"; import { CodexSdk } from "./sdk/codex"; import { ErrorPlaceholder } from "./components/ErrorPlaceholder/ErrorPlaceholder.tsx"; -if (import.meta.env.PROD) { +if (import.meta.env.PROD && !import.meta.env.CI) { Sentry.init({ release: "codex-storage-marketplace-ui@" + import.meta.env.PACKAGE_VERSION, dsn: "https://22d77c59a27b8d5efc07132188b505b9@o4507855852011520.ingest.de.sentry.io/4507866758512720", diff --git a/src/proxy.ts b/src/proxy.ts index a78af36..0340507 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -3,12 +3,10 @@ import { CodexData, CodexDataResponse, CodexMarketplace, - CodexReservation, SafeValue, UploadResponse, } from "@codex-storage/sdk-js"; import { CodexSdk as Sdk } from "./sdk/codex"; -import { WebStorage } from "./utils/web-storage"; import { FilesStorage } from "./utils/file-storage"; import { PurchaseStorage } from "./utils/purchases-storage"; @@ -17,15 +15,58 @@ class CodexDataMock extends CodexData { file: File, onProgress?: (loaded: number, total: number) => void ): UploadResponse { + // const url = CodexSdk.url() + "/api/codex/v1/data"; + + // const xhr = new XMLHttpRequest(); + + // const promise = new Promise>((resolve) => { + // xhr.upload.onprogress = (evt) => { + // if (evt.lengthComputable) { + // onProgress?.(evt.loaded, evt.total); + // } + // }; + + // xhr.open("POST", url, true); + // xhr.setRequestHeader("Content-Disposition", "attachment; filename=\"" + file.name + "\"") + // xhr.send(file); + + // xhr.onload = function () { + // if (xhr.status != 200) { + // resolve({ + // error: true, + // data: new CodexError(xhr.responseText, { + // code: xhr.status, + // }), + // }); + // } else { + // resolve({ error: false, data: xhr.response }); + // } + // }; + + // xhr.onerror = function () { + // resolve({ + // error: true, + // data: new CodexError("Something went wrong during the file upload."), + // }); + // }; + // }); + + // return { + // result: promise, + // abort: () => { + // xhr.abort(); + // }, + // }; const { result, abort } = super.upload(file, onProgress); return { abort, result: result.then((safe) => { if (!safe.error) { - return WebStorage.set(safe.data, { - type: file.type, + return FilesStorage.set(safe.data, { + mimetype: file.type, name: file.name, + uploadedAt: new Date().toJSON(), }).then(() => safe); } @@ -143,39 +184,39 @@ class CodexMarketplaceMock extends CodexMarketplace { // }, // }); // } - override reservations(): Promise> { - return Promise.resolve({ - error: false, - data: [ - { - id: "0x123456789", - availabilityId: "0x12345678910", - requestId: "0x1234567891011", - /** - * Size in bytes - */ - size: 500_000_000 + "", - /** - * Slot Index as hexadecimal string - */ - slotIndex: "2", - }, - { - id: "0x987654321", - availabilityId: "0x9876543210", - requestId: "0x98765432100", - /** - * Size in bytes - */ - size: 500_000_000 + "", - /** - * Slot Index as hexadecimal string - */ - slotIndex: "1", - }, - ], - }); - } + // override reservations(): Promise> { + // return Promise.resolve({ + // error: false, + // data: [ + // { + // id: "0x123456789", + // availabilityId: "0x12345678910", + // requestId: "0x1234567891011", + // /** + // * Size in bytes + // */ + // size: 500_000_000 + "", + // /** + // * Slot Index as hexadecimal string + // */ + // slotIndex: "2", + // }, + // { + // id: "0x987654321", + // availabilityId: "0x9876543210", + // requestId: "0x98765432100", + // /** + // * Size in bytes + // */ + // size: 500_000_000 + "", + // /** + // * Slot Index as hexadecimal string + // */ + // slotIndex: "1", + // }, + // ], + // }); + // } } export const CodexSdk = { diff --git a/src/routes/dashboard.css b/src/routes/dashboard.css index aa86380..b43ee4a 100644 --- a/src/routes/dashboard.css +++ b/src/routes/dashboard.css @@ -5,6 +5,19 @@ gap: 0.75rem; } +.dashboard-download { + margin-top: 1rem; +} + +.dashboard-welcome { + display: flex; + flex-direction: column; +} + +.dashboard-alert { + margin-bottom: 0; +} + @media (min-width: 1000px) { .dashboard { grid-template-columns: repeat(2, minmax(0, 1fr)); diff --git a/src/routes/dashboard/index.tsx b/src/routes/dashboard/index.tsx index 7318db7..931438f 100644 --- a/src/routes/dashboard/index.tsx +++ b/src/routes/dashboard/index.tsx @@ -1,11 +1,12 @@ import { createFileRoute } from "@tanstack/react-router"; import { Files } from "../../components/Files/Files.tsx"; -import { Card, Upload } from "@codex-storage/marketplace-ui-components"; +import { Alert, Card, Upload } from "@codex-storage/marketplace-ui-components"; import { CodexSdk } from "../../sdk/codex"; import { Welcome } from "../../components/Welcome/Welcome.tsx"; import { ErrorPlaceholder } from "../../components/ErrorPlaceholder/ErrorPlaceholder.tsx"; import { ErrorBoundary } from "@sentry/react"; import { useQueryClient } from "@tanstack/react-query"; +import { Download } from "../../components/Download/Download.tsx"; export const Route = createFileRoute("/dashboard/")({ component: About, @@ -21,21 +22,35 @@ function About() { return ( <>
- ( - - )}> - - - - +
+ ( + + )}> + + + + + + ( + + )}> + + + + +
( @@ -44,7 +59,17 @@ function About() { subtitle="Cannot retrieve the data." /> )}> - +
+ + + + The website and the content herein is not intended for public use + and is for informational and demonstration purposes only. + +
diff --git a/src/routes/dashboard/peers.tsx b/src/routes/dashboard/peers.tsx index de64e21..491e867 100644 --- a/src/routes/dashboard/peers.tsx +++ b/src/routes/dashboard/peers.tsx @@ -9,6 +9,8 @@ import { useCallback, useState } from "react"; import { PeerPin } from "../../components/Peers/types"; import "./peers.css"; import { CodexSdk } from "../../sdk/codex"; +import { ErrorBoundary } from "@sentry/react"; +import { ErrorPlaceholder } from "../../components/ErrorPlaceholder/ErrorPlaceholder"; // This function accepts the same arguments as DottedMap in the example above. const mapJsonString = getMapJSON({ height: 60, grid: "diagonal" }); @@ -102,5 +104,12 @@ const Peers = () => { }; export const Route = createFileRoute("/dashboard/peers")({ - component: Peers, + component: () => ( + ( + + )}> + + + ), }); diff --git a/src/routes/dashboard/settings.tsx b/src/routes/dashboard/settings.tsx index 48e56a7..e46deee 100644 --- a/src/routes/dashboard/settings.tsx +++ b/src/routes/dashboard/settings.tsx @@ -5,6 +5,7 @@ import { Debug } from "../../components/Debug/Debug"; import { CodexUrlSettings } from "../../components/CodexUrllSettings/CodexUrlSettings"; import { ErrorBoundary } from "@sentry/react"; import { ErrorPlaceholder } from "../../components/ErrorPlaceholder/ErrorPlaceholder"; +import { useEffect } from "react"; export const Route = createFileRoute("/dashboard/settings")({ component: () => ( @@ -35,12 +36,25 @@ export const Route = createFileRoute("/dashboard/settings")({
( - - )}> + fallback={({ error, resetError }) => { + useEffect(() => { + document.addEventListener("codexinvalidatequeries", resetError); + + return () => { + document.removeEventListener( + "codexinvalidatequeries", + resetError + ); + }; + }, [resetError]); + + return ( + + ); + }}>
diff --git a/src/utils/errors.ts b/src/utils/errors.ts index 2b41d02..90a085a 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,9 +1,13 @@ import * as Sentry from "@sentry/browser"; import { CodexError } from "@codex-storage/sdk-js"; - export const Errors = { report(safe: { error: true, data: CodexError }) { + if (safe.data.code === 502) { + // Ignore Gateway error + return + } + Sentry.captureException(safe.data, { extra: { code: safe.data.code,