diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 42ea7b619..dcc852e59 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,173 +1,173 @@ -name: Run Autumn Tests +# name: Run Autumn Tests -on: - workflow_dispatch: - push: - branches: - - main -env: - DATABASE_URL: ${{ secrets.SUPABASE_URL }} - UNIT_TEST_AUTUMN_SECRET_KEY: ${{ secrets.AUTUMN_KEY }} - REDIS_URL: redis://localhost:6379 - ENCRYPTION_IV: ${{ secrets.ENCRYPTION_IV }} - ENCRYPTION_PASSWORD: ${{ secrets.ENCRYPTION_PASSWORD }} - TESTS_ORG: ${{ secrets.TESTS_ORG }} - TESTS_ORG_ID: ${{ secrets.TESTS_ORG_ID }} - LOCALTUNNEL_RESERVED_KEY: ${{ secrets.LOCALTUNNEL_RESERVED_KEY }} - STRIPE_WEBHOOK_URL: ${{ secrets.STRIPE_WEBHOOK_URL }} - BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }} - HYPERBROWSER_API_KEY: ${{ secrets.HYPERBROWSER_API_KEY }} - STRIPE_TEST_KEY: ${{ secrets.STRIPE_TEST_KEY }} +# on: +# workflow_dispatch: +# push: +# branches: +# - main +# env: +# DATABASE_URL: ${{ secrets.SUPABASE_URL }} +# UNIT_TEST_AUTUMN_SECRET_KEY: ${{ secrets.AUTUMN_KEY }} +# REDIS_URL: redis://localhost:6379 +# ENCRYPTION_IV: ${{ secrets.ENCRYPTION_IV }} +# ENCRYPTION_PASSWORD: ${{ secrets.ENCRYPTION_PASSWORD }} +# TESTS_ORG: ${{ secrets.TESTS_ORG }} +# TESTS_ORG_ID: ${{ secrets.TESTS_ORG_ID }} +# LOCALTUNNEL_RESERVED_KEY: ${{ secrets.LOCALTUNNEL_RESERVED_KEY }} +# STRIPE_WEBHOOK_URL: ${{ secrets.STRIPE_WEBHOOK_URL }} +# BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }} +# HYPERBROWSER_API_KEY: ${{ secrets.HYPERBROWSER_API_KEY }} +# STRIPE_TEST_KEY: ${{ secrets.STRIPE_TEST_KEY }} -jobs: - test: - runs-on: blacksmith-4vcpu-ubuntu-2404 - # runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4.2.2 +# jobs: +# test: +# runs-on: blacksmith-4vcpu-ubuntu-2404 +# # runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v4.2.2 - - name: Set up bun - uses: oven-sh/setup-bun@v2 +# - name: Set up bun +# uses: oven-sh/setup-bun@v2 - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' +# - name: Set up Node.js +# uses: actions/setup-node@v4 +# with: +# node-version: '22' - - name: Install dependencies - # run: bun install --no-frozen-lockfile - run: bun install +# - name: Install dependencies +# # run: bun install --no-frozen-lockfile +# run: bun install - - name: Setup CI - run: bun run setupci +# - name: Setup CI +# run: bun run setupci - # - name: Install Chrome Dependencies - # run: | - # sudo apt-get update - # sudo apt-get install -y \ - # ca-certificates \ - # fonts-liberation \ - # libasound2 \ - # libatk-bridge2.0-0 \ - # libatk1.0-0 \ - # libc6 \ - # libcairo2 \ - # libcups2 \ - # libdbus-1-3 \ - # libexpat1 \ - # libfontconfig1 \ - # libgbm1 \ - # libgcc1 \ - # libgdk-pixbuf2.0-0 \ - # libglib2.0-0 \ - # libgtk-3-0 \ - # libnspr4 \ - # libnss3 \ - # libpango-1.0-0 \ - # libpangocairo-1.0-0 \ - # libstdc++6 \ - # libx11-6 \ - # libx11-xcb1 \ - # libxcb1 \ - # libxcomposite1 \ - # libxcursor1 \ - # libxdamage1 \ - # libxext6 \ - # libxfixes3 \ - # libxi6 \ - # libxrandr2 \ - # libxrender1 \ - # libxss1 \ - # libxtst6 \ - # lsb-release \ - # wget \ - # xdg-utils +# # - name: Install Chrome Dependencies +# # run: | +# # sudo apt-get update +# # sudo apt-get install -y \ +# # ca-certificates \ +# # fonts-liberation \ +# # libasound2 \ +# # libatk-bridge2.0-0 \ +# # libatk1.0-0 \ +# # libc6 \ +# # libcairo2 \ +# # libcups2 \ +# # libdbus-1-3 \ +# # libexpat1 \ +# # libfontconfig1 \ +# # libgbm1 \ +# # libgcc1 \ +# # libgdk-pixbuf2.0-0 \ +# # libglib2.0-0 \ +# # libgtk-3-0 \ +# # libnspr4 \ +# # libnss3 \ +# # libpango-1.0-0 \ +# # libpangocairo-1.0-0 \ +# # libstdc++6 \ +# # libx11-6 \ +# # libx11-xcb1 \ +# # libxcb1 \ +# # libxcomposite1 \ +# # libxcursor1 \ +# # libxdamage1 \ +# # libxext6 \ +# # libxfixes3 \ +# # libxi6 \ +# # libxrandr2 \ +# # libxrender1 \ +# # libxss1 \ +# # libxtst6 \ +# # lsb-release \ +# # wget \ +# # xdg-utils - # - name: Install Chrome - # run: | - # cd server/ - # npx puppeteer browsers install chrome +# # - name: Install Chrome +# # run: | +# # cd server/ +# # npx puppeteer browsers install chrome - - name: Create .env file - run: | - echo "Creating .env file..." - echo "DATABASE_URL=${{ env.DATABASE_URL }}" >> .env - echo "UNIT_TEST_AUTUMN_SECRET_KEY=${{ env.UNIT_TEST_AUTUMN_SECRET_KEY }}" >> .env - echo "REDIS_URL=${{ env.REDIS_URL }}" >> .env - echo "ENCRYPTION_IV=${{ env.ENCRYPTION_IV }}" >> .env - echo "ENCRYPTION_PASSWORD=${{ env.ENCRYPTION_PASSWORD }}" >> .env - echo "TESTS_ORG=${{ env.TESTS_ORG }}" >> .env - echo "TESTS_ORG_ID=${{ env.TESTS_ORG_ID }}" >> .env - echo "LOCALTUNNEL_RESERVED_KEY=${{ env.LOCALTUNNEL_RESERVED_KEY }}" >> .env - echo "BETTER_AUTH_SECRET=${{ env.BETTER_AUTH_SECRET }}" >> .env - echo "HYPERBROWSER_API_KEY=${{ env.HYPERBROWSER_API_KEY }}" >> .env - echo "STRIPE_TEST_KEY=${{ env.STRIPE_TEST_KEY }}" >> .env - echo "STRIPE_WEBHOOK_URL=${{ env.STRIPE_WEBHOOK_URL }}" >> .env - cat .env +# - name: Create .env file +# run: | +# echo "Creating .env file..." +# echo "DATABASE_URL=${{ env.DATABASE_URL }}" >> .env +# echo "UNIT_TEST_AUTUMN_SECRET_KEY=${{ env.UNIT_TEST_AUTUMN_SECRET_KEY }}" >> .env +# echo "REDIS_URL=${{ env.REDIS_URL }}" >> .env +# echo "ENCRYPTION_IV=${{ env.ENCRYPTION_IV }}" >> .env +# echo "ENCRYPTION_PASSWORD=${{ env.ENCRYPTION_PASSWORD }}" >> .env +# echo "TESTS_ORG=${{ env.TESTS_ORG }}" >> .env +# echo "TESTS_ORG_ID=${{ env.TESTS_ORG_ID }}" >> .env +# echo "LOCALTUNNEL_RESERVED_KEY=${{ env.LOCALTUNNEL_RESERVED_KEY }}" >> .env +# echo "BETTER_AUTH_SECRET=${{ env.BETTER_AUTH_SECRET }}" >> .env +# echo "HYPERBROWSER_API_KEY=${{ env.HYPERBROWSER_API_KEY }}" >> .env +# echo "STRIPE_TEST_KEY=${{ env.STRIPE_TEST_KEY }}" >> .env +# echo "STRIPE_WEBHOOK_URL=${{ env.STRIPE_WEBHOOK_URL }}" >> .env +# cat .env - - name: Build shared - run: | - cd shared - bun run build +# - name: Build shared +# run: | +# cd shared +# bun run build - - name: Startup server - run: sudo docker compose -f docker-compose.ci.yml up --detach +# - name: Startup server +# run: sudo docker compose -f docker-compose.ci.yml up --detach - - name: Wait for server to be ready - run: | - echo "Waiting for server to start..." - timeout 120s bash -c 'until curl -s --fail http://localhost:8080; do echo "Waiting..."; sleep 2; done' - echo "Server is up!" +# - name: Wait for server to be ready +# run: | +# echo "Waiting for server to start..." +# timeout 120s bash -c 'until curl -s --fail http://localhost:8080; do echo "Waiting..."; sleep 2; done' +# echo "Server is up!" - - name: Ping Local Tunnel - run: | - echo "Pinging Local Tunnel..." - curl https://askjdnaslkjdalkjen.loca.lt - echo "Local Tunnel pinged!" +# - name: Ping Local Tunnel +# run: | +# echo "Pinging Local Tunnel..." +# curl https://askjdnaslkjdalkjen.loca.lt +# echo "Local Tunnel pinged!" - - name: Run G2 tests - run: | - cd server/ - chmod +x ./shell/g2.sh - ./shell/g2.sh setup +# - name: Run G2 tests +# run: | +# cd server/ +# chmod +x ./shell/g2.sh +# ./shell/g2.sh setup - - name: Run G3 tests - run: | - cd server/ - chmod +x ./shell/g3.sh - ./shell/g3.sh +# - name: Run G3 tests +# run: | +# cd server/ +# chmod +x ./shell/g3.sh +# ./shell/g3.sh - - name: Run G4 tests - run: | - cd server/ - chmod +x ./shell/g4.sh - ./shell/g4.sh +# - name: Run G4 tests +# run: | +# cd server/ +# chmod +x ./shell/g4.sh +# ./shell/g4.sh - - name: Run G5 tests - run: | - cd server/ - chmod +x ./shell/g5.sh - ./shell/g4.sh +# - name: Run G5 tests +# run: | +# cd server/ +# chmod +x ./shell/g5.sh +# ./shell/g4.sh - # - name: Run G4 tests - # run: | - # cd server/ - # chmod +x ./shell/g4.sh - # ./shell/g4.sh +# # - name: Run G4 tests +# # run: | +# # cd server/ +# # chmod +x ./shell/g4.sh +# # ./shell/g4.sh - # - name: Message - # run: - # echo "We're all setup!" +# # - name: Message +# # run: +# # echo "We're all setup!" - # - name: Check logs - # if: always() - # run: sudo docker compose -f docker-compose.ci.yml logs server - - name: Check logs - if: always() - run: sudo docker compose -f docker-compose.ci.yml logs localtunnel +# # - name: Check logs +# # if: always() +# # run: sudo docker compose -f docker-compose.ci.yml logs server +# - name: Check logs +# if: always() +# run: sudo docker compose -f docker-compose.ci.yml logs localtunnel - - name: Close Docker Containers - if: always() - run: sudo docker compose -f docker-compose.ci.yml down \ No newline at end of file +# - name: Close Docker Containers +# if: always() +# run: sudo docker compose -f docker-compose.ci.yml down \ No newline at end of file diff --git a/bun.lock b/bun.lock index d5e5598ed..ab973be92 100644 --- a/bun.lock +++ b/bun.lock @@ -47,7 +47,7 @@ "@supabase/supabase-js": "^2.46.2", "@upstash/redis": "^1.35.1", "ai": "^4.3.10", - "autumn-js": "^0.1.4", + "autumn-js": "^0.1.8", "axios": "^1.8.3", "better-auth": "^1.2.9", "body-parser": "^1.20.3", @@ -253,15 +253,15 @@ "@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="], - "@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], + "@babel/core": ["@babel/core@7.28.3", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ=="], - "@babel/generator": ["@babel/generator@7.28.0", "", { "dependencies": { "@babel/parser": "^7.28.0", "@babel/types": "^7.28.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg=="], + "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], - "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.27.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A=="], + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.3", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg=="], "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], @@ -269,7 +269,7 @@ "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg=="], + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], @@ -285,9 +285,9 @@ "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - "@babel/helpers": ["@babel/helpers@7.28.2", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw=="], + "@babel/helpers": ["@babel/helpers@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw=="], - "@babel/parser": ["@babel/parser@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.0" }, "bin": "./bin/babel-parser.js" }, "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g=="], + "@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], "@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.11", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-create-class-features-plugin": "^7.21.0", "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw=="], @@ -297,41 +297,41 @@ "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], - "@babel/runtime": ["@babel/runtime@7.28.2", "", {}, "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="], + "@babel/runtime": ["@babel/runtime@7.28.3", "", {}, "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA=="], "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - "@babel/traverse": ["@babel/traverse@7.28.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/types": "^7.28.0", "debug": "^4.3.1" } }, "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg=="], + "@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], "@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="], - "@better-auth/stripe": ["@better-auth/stripe@1.3.4", "", { "dependencies": { "better-auth": "^1.3.4", "zod": "^4.0.0" } }, "sha512-sFHEOvLDwKe0ZYxqNTlfoshekiXkomnAcOEH7ARq0r7XImpPjpUR+GHc9+0CGTXTCn3LYljmBt0paTX1rhRNjw=="], + "@better-auth/stripe": ["@better-auth/stripe@1.3.6", "", { "dependencies": { "better-auth": "^1.3.6" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-f4tsO5DLEOS1FhzpEE5QxtYjgxaAluy9ut9QsBp5uXx3dh38iFUOfrUuJTwxo2EdoqsEiRyIcFxH9ikMuzPrpQ=="], - "@better-auth/utils": ["@better-auth/utils@0.2.5", "", { "dependencies": { "typescript": "^5.8.2", "uncrypto": "^0.1.3" } }, "sha512-uI2+/8h/zVsH8RrYdG8eUErbuGBk16rZKQfz8CjxQOyCE6v7BqFYEbFwvOkvl1KbUdxhqOnXp78+uE5h8qVEgQ=="], + "@better-auth/utils": ["@better-auth/utils@0.2.6", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-3y/vaL5Ox33dBwgJ6ub3OPkVqr6B5xL2kgxNHG8eHZuryLyG/4JSPGqjbdRSgjuy9kALUZYDFl+ORIAxlWMSuA=="], "@better-fetch/fetch": ["@better-fetch/fetch@1.1.18", "", {}, "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="], "@browserbasehq/sdk": ["@browserbasehq/sdk@2.6.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-83iXP5D7xMm8Wyn66TUaUrgoByCmAJuoMoZQI3sGg3JAiMlTfnCIMqyVBoNSaItaPIkaCnrsj6LiusmXV2X9YA=="], - "@clerk/backend": ["@clerk/backend@2.6.3", "", { "dependencies": { "@clerk/shared": "^3.18.0", "@clerk/types": "^4.73.0", "cookie": "1.0.2", "standardwebhooks": "^1.0.0", "tslib": "2.8.1" } }, "sha512-x73eu/zDMc1E2YvvW+KW55B6BOfiUrgFhSJngBsZJ6+W5hWZph+XeCS7oEcZfhvQyUcb9M6tqM2R1w7htNgh1Q=="], + "@clerk/backend": ["@clerk/backend@2.9.1", "", { "dependencies": { "@clerk/shared": "^3.21.0", "@clerk/types": "^4.78.0", "cookie": "1.0.2", "standardwebhooks": "^1.0.0", "tslib": "2.8.1" } }, "sha512-ZRvy4cHpCrOORtyB3xixifek5/Tsc+X5pkC4vVBrZyqntcRsqhO58eSwb4O4rba6gE9UpVhTYnP1+DVLLiyTJw=="], - "@clerk/clerk-react": ["@clerk/clerk-react@5.39.0", "", { "dependencies": { "@clerk/shared": "^3.18.0", "@clerk/types": "^4.73.0", "tslib": "2.8.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" } }, "sha512-c1GJMj8wrzFrT3BbvZ4JwYY91BAY1M4yMypaAs3UNvtU0dDze7bmUVs02eW+z0GgaEQbGBVO4f5ru/pBXCGSKA=="], + "@clerk/clerk-react": ["@clerk/clerk-react@5.42.1", "", { "dependencies": { "@clerk/shared": "^3.21.0", "@clerk/types": "^4.78.0", "tslib": "2.8.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" } }, "sha512-6CuOY0QttPU2uimzTTVEEeH0mKo4xQVhaUN8Iqe+Z6nIwYLOTa2w4Lk8wAqEQHWbd1WBOAkP3b+7c/QToWTH7A=="], - "@clerk/express": ["@clerk/express@1.7.16", "", { "dependencies": { "@clerk/backend": "^2.6.3", "@clerk/shared": "^3.18.0", "@clerk/types": "^4.73.0", "tslib": "2.8.1" }, "peerDependencies": { "express": "^4.17.0 || ^5.0.0" } }, "sha512-T+Gw0vjRl9gRG1aEFfJVf3EQ9r6jfHtvOq9NU4q64GrsgvCZmvhjsx514sx3mqKfXM5CzFnT5biUpNwY27aAwQ=="], + "@clerk/express": ["@clerk/express@1.7.21", "", { "dependencies": { "@clerk/backend": "^2.9.1", "@clerk/shared": "^3.21.0", "@clerk/types": "^4.78.0", "tslib": "2.8.1" }, "peerDependencies": { "express": "^4.17.0 || ^5.0.0" } }, "sha512-ALtBBhaYU+gfRoJp25hC3OntbNNgcrvLSyIYVShSCQ8gmyFjrJe/u6wb2PJalKtiE0SJUZPCAPCr8QpWSXEIsg=="], - "@clerk/shared": ["@clerk/shared@3.18.0", "", { "dependencies": { "@clerk/types": "^4.73.0", "dequal": "2.0.3", "glob-to-regexp": "0.4.1", "js-cookie": "3.0.5", "std-env": "^3.9.0", "swr": "2.3.4" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-QGYbtPfJEp66AgaI0JtiRX04ejoUI8SmqUqqbAm3UXAeUAsKOyXoNbghNal97X7qeq1vPRRiDugK5B9WYN69uA=="], + "@clerk/shared": ["@clerk/shared@3.21.0", "", { "dependencies": { "@clerk/types": "^4.78.0", "dequal": "2.0.3", "glob-to-regexp": "0.4.1", "js-cookie": "3.0.5", "std-env": "^3.9.0", "swr": "2.3.4" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-BlIjPLsw2ral0V2sDDTNxoSK3SLLT6tfKiTJG2I3vQILnrGPEwkiEaMY1+bJtOze7EHdpP2KSsTzzjFTP1UDOg=="], - "@clerk/types": ["@clerk/types@4.73.0", "", { "dependencies": { "csstype": "3.1.3" } }, "sha512-SFM29RFVqs0KyTds3F7s7DBYNoqeBDSZiWuso/WCgfQVI4H3j0gI+0BdBEiqwCILXr4jKBG2srDmzP5FVvx8Hg=="], + "@clerk/types": ["@clerk/types@4.78.0", "", { "dependencies": { "csstype": "3.1.3" } }, "sha512-wj52aLAH8RrZmHSNTNJIvxwyCuBMNRP2THOshFwpt0Vg62GQi6NtMLRqNH3Pc5y+zrg42SzLiO31PTNZh3ddpQ=="], - "@clickhouse/client": ["@clickhouse/client@1.12.0", "", { "dependencies": { "@clickhouse/client-common": "1.12.0" } }, "sha512-vJUSX8THhTzlVn0WxPukVjOgNRaSoY02ubQkB0LpqNoHFxXuF5jQZZAYvGZWpBGbYQ/4gfPrqu8g4TX5UKeNxA=="], + "@clickhouse/client": ["@clickhouse/client@1.12.1", "", { "dependencies": { "@clickhouse/client-common": "1.12.1" } }, "sha512-7ORY85rphRazqHzImNXMrh4vsaPrpetFoTWpZYueCO2bbO6PXYDXp/GQ4DgxnGIqbWB/Di1Ai+Xuwq2o7DJ36A=="], - "@clickhouse/client-common": ["@clickhouse/client-common@1.12.0", "", {}, "sha512-cyI4n7u9jK30d9q1q0ceQ7IwJ/MtTs5HxoQfc8yHpN+ok5wqaU2jAtq5hpa1z7C7sS1pDy/ZOFmOzg1v1F683g=="], + "@clickhouse/client-common": ["@clickhouse/client-common@1.12.1", "", {}, "sha512-ccw1N6hB4+MyaAHIaWBwGZ6O2GgMlO99FlMj0B0UEGfjxM9v5dYVYql6FpP19rMwrVAroYs/IgX2vyZEBvzQLg=="], "@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="], "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], - "@date-fns/tz": ["@date-fns/tz@1.3.1", "", {}, "sha512-LnBOyuj+piItX/D5BWBSckBsuZyOt7Jg2obGNiObq7qjl1A2/8F+i4RS8/MmkSdnw6hOe6afrJLCWrUWZw5Mlw=="], + "@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="], "@date-fns/utc": ["@date-fns/utc@2.1.1", "", {}, "sha512-SlJDfG6RPeEX8wEVv6ZB3kak4MmbtyiI2qX/5zuKdordbrhB/iaJ58GVMZgJ6P1sJaM1gMgENFYYeg1JWrCFrA=="], @@ -347,57 +347,57 @@ "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.8", "", { "os": "aix", "cpu": "ppc64" }, "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.9", "", { "os": "aix", "cpu": "ppc64" }, "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.8", "", { "os": "android", "cpu": "arm" }, "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.9", "", { "os": "android", "cpu": "arm" }, "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.8", "", { "os": "android", "cpu": "arm64" }, "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.9", "", { "os": "android", "cpu": "arm64" }, "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.8", "", { "os": "android", "cpu": "x64" }, "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.9", "", { "os": "android", "cpu": "x64" }, "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.8", "", { "os": "linux", "cpu": "arm" }, "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.9", "", { "os": "linux", "cpu": "arm" }, "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.8", "", { "os": "linux", "cpu": "ia32" }, "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.9", "", { "os": "linux", "cpu": "ia32" }, "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.8", "", { "os": "linux", "cpu": "x64" }, "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.9", "", { "os": "linux", "cpu": "x64" }, "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.8", "", { "os": "none", "cpu": "x64" }, "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.9", "", { "os": "none", "cpu": "x64" }, "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.8", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.9", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.8", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.9", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.8", "", { "os": "sunos", "cpu": "x64" }, "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.9", "", { "os": "sunos", "cpu": "x64" }, "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.8", "", { "os": "win32", "cpu": "x64" }, "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.9", "", { "os": "win32", "cpu": "x64" }, "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ=="], "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], @@ -405,17 +405,17 @@ "@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="], - "@eslint/config-helpers": ["@eslint/config-helpers@0.3.0", "", {}, "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw=="], + "@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="], - "@eslint/core": ["@eslint/core@0.15.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA=="], + "@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="], "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], - "@eslint/js": ["@eslint/js@9.32.0", "", {}, "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg=="], + "@eslint/js": ["@eslint/js@9.33.0", "", {}, "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A=="], "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.4", "", { "dependencies": { "@eslint/core": "^0.15.1", "levn": "^0.4.1" } }, "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw=="], + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="], "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], @@ -499,16 +499,18 @@ "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.3", "", { "os": "win32", "cpu": "x64" }, "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g=="], - "@inquirer/checkbox": ["@inquirer/checkbox@4.2.0", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA=="], + "@inquirer/checkbox": ["@inquirer/checkbox@4.2.1", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-bevKGO6kX1eM/N+pdh9leS5L7TBF4ICrzi9a+cbWkrxeAeIcwlo/7OfWGCDERdRCI2/Q6tjltX4bt07ALHDwFw=="], "@inquirer/confirm": ["@inquirer/confirm@5.1.14", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q=="], "@inquirer/core": ["@inquirer/core@10.1.15", "", { "dependencies": { "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA=="], - "@inquirer/editor": ["@inquirer/editor@4.2.15", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8", "external-editor": "^3.1.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ=="], + "@inquirer/editor": ["@inquirer/editor@4.2.17", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/external-editor": "^1.0.1", "@inquirer/type": "^3.0.8" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-r6bQLsyPSzbWrZZ9ufoWL+CztkSatnJ6uSxqd6N+o41EZC51sQeWOzI6s5jLb+xxTWxl7PlUppqm8/sow241gg=="], "@inquirer/expand": ["@inquirer/expand@4.0.17", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw=="], + "@inquirer/external-editor": ["@inquirer/external-editor@1.0.1", "", { "dependencies": { "chardet": "^2.1.0", "iconv-lite": "^0.6.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q=="], + "@inquirer/figures": ["@inquirer/figures@1.0.13", "", {}, "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw=="], "@inquirer/input": ["@inquirer/input@4.2.1", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow=="], @@ -517,7 +519,7 @@ "@inquirer/password": ["@inquirer/password@4.0.17", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA=="], - "@inquirer/prompts": ["@inquirer/prompts@7.8.0", "", { "dependencies": { "@inquirer/checkbox": "^4.2.0", "@inquirer/confirm": "^5.1.14", "@inquirer/editor": "^4.2.15", "@inquirer/expand": "^4.0.17", "@inquirer/input": "^4.2.1", "@inquirer/number": "^3.0.17", "@inquirer/password": "^4.0.17", "@inquirer/rawlist": "^4.1.5", "@inquirer/search": "^3.1.0", "@inquirer/select": "^4.3.1" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-JHwGbQ6wjf1dxxnalDYpZwZxUEosT+6CPGD9Zh4sm9WXdtUp9XODCQD3NjSTmu+0OAyxWXNOqf0spjIymJa2Tw=="], + "@inquirer/prompts": ["@inquirer/prompts@7.8.2", "", { "dependencies": { "@inquirer/checkbox": "^4.2.1", "@inquirer/confirm": "^5.1.14", "@inquirer/editor": "^4.2.17", "@inquirer/expand": "^4.0.17", "@inquirer/input": "^4.2.1", "@inquirer/number": "^3.0.17", "@inquirer/password": "^4.0.17", "@inquirer/rawlist": "^4.1.5", "@inquirer/search": "^3.1.0", "@inquirer/select": "^4.3.1" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw=="], "@inquirer/rawlist": ["@inquirer/rawlist@4.1.5", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA=="], @@ -537,11 +539,13 @@ "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.4", "", {}, "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], @@ -795,15 +799,15 @@ "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], - "@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], - "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collapsible": "1.1.11", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A=="], + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], - "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA=="], + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="], - "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg=="], + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], @@ -811,47 +815,47 @@ "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], - "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw=="], + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], - "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ=="], + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], - "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ=="], + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="], - "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA=="], + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], - "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.10", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew=="], + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], - "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw=="], + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], - "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ=="], + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], - "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="], + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q=="], + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], - "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.9", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YSjEfBXnhUELsO2VzjdtYYD4CfQjvao+lhhrX5XsHD7/cyUNzljF1FHEbgTPN7LH2MClfwRMIsYlqTYpKTTe2A=="], + "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], - "@radix-ui/react-select": ["@radix-ui/react-select@2.2.5", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA=="], + "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="], "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], - "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ=="], + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], - "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw=="], + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], - "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw=="], + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], @@ -961,13 +965,13 @@ "@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="], - "@sentry/core": ["@sentry/core@9.44.2", "", {}, "sha512-4wduCY9vz+VRMZXTT1dzk08L2nReeR+lzpY8hCcc+Wu100BoJR+TNlrSn1rG5iIo98NDW860JsRA7SVDUDOiNQ=="], + "@sentry/core": ["@sentry/core@9.46.0", "", {}, "sha512-it7JMFqxVproAgEtbLgCVBYtQ9fIb+Bu0JD+cEplTN/Ukpe6GaolyYib5geZqslVxhp2sQgT+58aGvfd/k0N8Q=="], - "@sentry/node": ["@sentry/node@9.44.2", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1", "@opentelemetry/core": "^1.30.1", "@opentelemetry/instrumentation": "^0.57.2", "@opentelemetry/instrumentation-amqplib": "^0.46.1", "@opentelemetry/instrumentation-connect": "0.43.1", "@opentelemetry/instrumentation-dataloader": "0.16.1", "@opentelemetry/instrumentation-express": "0.47.1", "@opentelemetry/instrumentation-fs": "0.19.1", "@opentelemetry/instrumentation-generic-pool": "0.43.1", "@opentelemetry/instrumentation-graphql": "0.47.1", "@opentelemetry/instrumentation-hapi": "0.45.2", "@opentelemetry/instrumentation-http": "0.57.2", "@opentelemetry/instrumentation-ioredis": "0.47.1", "@opentelemetry/instrumentation-kafkajs": "0.7.1", "@opentelemetry/instrumentation-knex": "0.44.1", "@opentelemetry/instrumentation-koa": "0.47.1", "@opentelemetry/instrumentation-lru-memoizer": "0.44.1", "@opentelemetry/instrumentation-mongodb": "0.52.0", "@opentelemetry/instrumentation-mongoose": "0.46.1", "@opentelemetry/instrumentation-mysql": "0.45.1", "@opentelemetry/instrumentation-mysql2": "0.45.2", "@opentelemetry/instrumentation-pg": "0.51.1", "@opentelemetry/instrumentation-redis-4": "0.46.1", "@opentelemetry/instrumentation-tedious": "0.18.1", "@opentelemetry/instrumentation-undici": "0.10.1", "@opentelemetry/resources": "^1.30.1", "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/semantic-conventions": "^1.34.0", "@prisma/instrumentation": "6.11.1", "@sentry/core": "9.44.2", "@sentry/node-core": "9.44.2", "@sentry/opentelemetry": "9.44.2", "import-in-the-middle": "^1.14.2", "minimatch": "^9.0.0" } }, "sha512-HTUDD73Tdr4GvvcNGQunkqEKeijHb4WYq/NX4YZP5VOeOsKsgIUsv55EgWk1BSHAFGTW6bfeMSoqaNVWiRHn0w=="], + "@sentry/node": ["@sentry/node@9.46.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1", "@opentelemetry/core": "^1.30.1", "@opentelemetry/instrumentation": "^0.57.2", "@opentelemetry/instrumentation-amqplib": "^0.46.1", "@opentelemetry/instrumentation-connect": "0.43.1", "@opentelemetry/instrumentation-dataloader": "0.16.1", "@opentelemetry/instrumentation-express": "0.47.1", "@opentelemetry/instrumentation-fs": "0.19.1", "@opentelemetry/instrumentation-generic-pool": "0.43.1", "@opentelemetry/instrumentation-graphql": "0.47.1", "@opentelemetry/instrumentation-hapi": "0.45.2", "@opentelemetry/instrumentation-http": "0.57.2", "@opentelemetry/instrumentation-ioredis": "0.47.1", "@opentelemetry/instrumentation-kafkajs": "0.7.1", "@opentelemetry/instrumentation-knex": "0.44.1", "@opentelemetry/instrumentation-koa": "0.47.1", "@opentelemetry/instrumentation-lru-memoizer": "0.44.1", "@opentelemetry/instrumentation-mongodb": "0.52.0", "@opentelemetry/instrumentation-mongoose": "0.46.1", "@opentelemetry/instrumentation-mysql": "0.45.1", "@opentelemetry/instrumentation-mysql2": "0.45.2", "@opentelemetry/instrumentation-pg": "0.51.1", "@opentelemetry/instrumentation-redis-4": "0.46.1", "@opentelemetry/instrumentation-tedious": "0.18.1", "@opentelemetry/instrumentation-undici": "0.10.1", "@opentelemetry/resources": "^1.30.1", "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/semantic-conventions": "^1.34.0", "@prisma/instrumentation": "6.11.1", "@sentry/core": "9.46.0", "@sentry/node-core": "9.46.0", "@sentry/opentelemetry": "9.46.0", "import-in-the-middle": "^1.14.2", "minimatch": "^9.0.0" } }, "sha512-pRLqAcd7GTGvN8gex5FtkQR5Mcol8gOy1WlyZZFq4rBbVtMbqKOQRhohwqnb+YrnmtFpj7IZ7KNDo077MvNeOQ=="], - "@sentry/node-core": ["@sentry/node-core@9.44.2", "", { "dependencies": { "@sentry/core": "9.44.2", "@sentry/opentelemetry": "9.44.2", "import-in-the-middle": "^1.14.2" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", "@opentelemetry/core": "^1.30.1 || ^2.0.0", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/resources": "^1.30.1 || ^2.0.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", "@opentelemetry/semantic-conventions": "^1.34.0" } }, "sha512-TnyKZQ4FOCA+mkLLaOzFPePUBRBf0FU62hnNMscJviwb0UloOvHXx4Ub1DudfFFdnIeVSSMU96ou8vW1zR/1Uw=="], + "@sentry/node-core": ["@sentry/node-core@9.46.0", "", { "dependencies": { "@sentry/core": "9.46.0", "@sentry/opentelemetry": "9.46.0", "import-in-the-middle": "^1.14.2" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", "@opentelemetry/core": "^1.30.1 || ^2.0.0", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/resources": "^1.30.1 || ^2.0.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", "@opentelemetry/semantic-conventions": "^1.34.0" } }, "sha512-XRVu5pqoklZeh4wqhxCLZkz/ipoKhitctgEFXX9Yh1e1BoHM2pIxT52wf+W6hHM676TFmFXW3uKBjsmRM3AjgA=="], - "@sentry/opentelemetry": ["@sentry/opentelemetry@9.44.2", "", { "dependencies": { "@sentry/core": "9.44.2" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", "@opentelemetry/core": "^1.30.1 || ^2.0.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", "@opentelemetry/semantic-conventions": "^1.34.0" } }, "sha512-KeW5MPXyq9Q8ieYUHO0PuzNNYEYizmTH6x02PG400GwmoeNxnT59Afa4TuPcrXN0QUmK76HJuPfC+7CTuCgoKA=="], + "@sentry/opentelemetry": ["@sentry/opentelemetry@9.46.0", "", { "dependencies": { "@sentry/core": "9.46.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", "@opentelemetry/core": "^1.30.1 || ^2.0.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", "@opentelemetry/semantic-conventions": "^1.34.0" } }, "sha512-w2zTxqrdmwRok0cXBoh+ksXdGRUHUZhlpfL/H2kfTodOL+Mk8rW72qUmfqQceXoqgbz8UyK8YgJbyt+XS5H4Qg=="], "@sentry/types": ["@sentry/types@8.55.0", "", { "dependencies": { "@sentry/core": "8.55.0" } }, "sha512-6LRT0+r6NWQ+RtllrUW2yQfodST0cJnkOmdpHA75vONgBUhpKwiJ4H7AmgfoTET8w29pU6AnntaGOe0LJbOmog=="], @@ -993,45 +997,45 @@ "@supabase/postgrest-js": ["@supabase/postgrest-js@1.19.4", "", { "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, "sha512-O4soKqKtZIW3olqmbXXbKugUtByD2jPa8kL2m2c1oozAO11uCcGrRhkZL0kVxjBLrXHE0mdSkFsMj7jDSfyNpw=="], - "@supabase/realtime-js": ["@supabase/realtime-js@2.11.15", "", { "dependencies": { "@supabase/node-fetch": "^2.6.13", "@types/phoenix": "^1.6.6", "@types/ws": "^8.18.1", "isows": "^1.0.7", "ws": "^8.18.2" } }, "sha512-HQKRnwAqdVqJW/P9TjKVK+/ETpW4yQ8tyDPPtRMKOH4Uh3vQD74vmj353CYs8+YwVBKubeUOOEpI9CT8mT4obw=="], + "@supabase/realtime-js": ["@supabase/realtime-js@2.15.1", "", { "dependencies": { "@supabase/node-fetch": "^2.6.13", "@types/phoenix": "^1.6.6", "@types/ws": "^8.18.1", "ws": "^8.18.2" } }, "sha512-edRFa2IrQw50kNntvUyS38hsL7t2d/psah6om6aNTLLcWem0R6bOUq7sk7DsGeSlNfuwEwWn57FdYSva6VddYw=="], "@supabase/ssr": ["@supabase/ssr@0.5.2", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.7.0" }, "peerDependencies": { "@supabase/supabase-js": "^2.43.4" } }, "sha512-n3plRhr2Bs8Xun1o4S3k1CDv17iH5QY9YcoEvXX3bxV1/5XSasA0mNXYycFmADIdtdE6BG9MRjP5CGIs8qxC8A=="], - "@supabase/storage-js": ["@supabase/storage-js@2.10.4", "", { "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, "sha512-cvL02GarJVFcNoWe36VBybQqTVRq6wQSOCvTS64C+eyuxOruFIm1utZAY0xi2qKtHJO3EjKaj8iWJKySusDmAQ=="], + "@supabase/storage-js": ["@supabase/storage-js@2.11.0", "", { "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, "sha512-Y+kx/wDgd4oasAgoAq0bsbQojwQ+ejIif8uczZ9qufRHWFLMU5cODT+ApHsSrDufqUcVKt+eyxtOXSkeh2v9ww=="], - "@supabase/supabase-js": ["@supabase/supabase-js@2.53.0", "", { "dependencies": { "@supabase/auth-js": "2.71.1", "@supabase/functions-js": "2.4.5", "@supabase/node-fetch": "2.6.15", "@supabase/postgrest-js": "1.19.4", "@supabase/realtime-js": "2.11.15", "@supabase/storage-js": "^2.10.4" } }, "sha512-Vg9sl0oFn55cCPaEOsDsRDbxOVccxRrK/cikjL1XbywHEOfyA5SOOEypidMvQLwgoAfnC2S4D9BQwJDcZs7/TQ=="], + "@supabase/supabase-js": ["@supabase/supabase-js@2.55.0", "", { "dependencies": { "@supabase/auth-js": "2.71.1", "@supabase/functions-js": "2.4.5", "@supabase/node-fetch": "2.6.15", "@supabase/postgrest-js": "1.19.4", "@supabase/realtime-js": "2.15.1", "@supabase/storage-js": "^2.10.4" } }, "sha512-Y1uV4nEMjQV1x83DGn7+Z9LOisVVRlY1geSARrUHbXWgbyKLZ6/08dvc0Us1r6AJ4tcKpwpCZWG9yDQYo1JgHg=="], "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], - "@tailwindcss/node": ["@tailwindcss/node@4.1.11", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.11" } }, "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.12", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.5.1", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.12" } }, "sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.11", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.11", "@tailwindcss/oxide-darwin-arm64": "4.1.11", "@tailwindcss/oxide-darwin-x64": "4.1.11", "@tailwindcss/oxide-freebsd-x64": "4.1.11", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", "@tailwindcss/oxide-linux-x64-musl": "4.1.11", "@tailwindcss/oxide-wasm32-wasi": "4.1.11", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" } }, "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.12", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.12", "@tailwindcss/oxide-darwin-arm64": "4.1.12", "@tailwindcss/oxide-darwin-x64": "4.1.12", "@tailwindcss/oxide-freebsd-x64": "4.1.12", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.12", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.12", "@tailwindcss/oxide-linux-arm64-musl": "4.1.12", "@tailwindcss/oxide-linux-x64-gnu": "4.1.12", "@tailwindcss/oxide-linux-x64-musl": "4.1.12", "@tailwindcss/oxide-wasm32-wasi": "4.1.12", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.12", "@tailwindcss/oxide-win32-x64-msvc": "4.1.12" } }, "sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.11", "", { "os": "android", "cpu": "arm64" }, "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.12", "", { "os": "android", "cpu": "arm64" }, "sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11", "", { "os": "linux", "cpu": "arm" }, "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12", "", { "os": "linux", "cpu": "arm" }, "sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.11", "", { "os": "linux", "cpu": "x64" }, "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.12", "", { "os": "linux", "cpu": "x64" }, "sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.11", "", { "os": "linux", "cpu": "x64" }, "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.12", "", { "os": "linux", "cpu": "x64" }, "sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.11", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.11", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.12", "", { "dependencies": { "@emnapi/core": "^1.4.5", "@emnapi/runtime": "^1.4.5", "@emnapi/wasi-threads": "^1.0.4", "@napi-rs/wasm-runtime": "^0.2.12", "@tybys/wasm-util": "^0.10.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.11", "", { "os": "win32", "cpu": "x64" }, "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.12", "", { "os": "win32", "cpu": "x64" }, "sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA=="], - "@tailwindcss/vite": ["@tailwindcss/vite@4.1.11", "", { "dependencies": { "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "tailwindcss": "4.1.11" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw=="], + "@tailwindcss/vite": ["@tailwindcss/vite@4.1.12", "", { "dependencies": { "@tailwindcss/node": "4.1.12", "@tailwindcss/oxide": "4.1.12", "tailwindcss": "4.1.12" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-4pt0AMFDx7gzIrAOIYgYP0KCBuKWqyW8ayrdiLEjoJTT4pKTjrzG/e4uzWtTLDziC+66R9wbUqZBccJalSE5vQ=="], "@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="], @@ -1059,7 +1063,7 @@ "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], - "@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="], + "@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="], "@types/bunyan": ["@types/bunyan@1.8.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ=="], @@ -1129,7 +1133,7 @@ "@types/mysql": ["@types/mysql@2.15.27", "", { "dependencies": { "@types/node": "*" } }, "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA=="], - "@types/node": ["@types/node@24.2.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw=="], + "@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="], "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], @@ -1181,41 +1185,41 @@ "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.39.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/type-utils": "8.39.0", "@typescript-eslint/utils": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.39.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.39.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.39.1", "@typescript-eslint/type-utils": "8.39.1", "@typescript-eslint/utils": "8.39.1", "@typescript-eslint/visitor-keys": "8.39.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.39.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-yYegZ5n3Yr6eOcqgj2nJH8cH/ZZgF+l0YIdKILSDjYFRjgYQMgv/lRjV5Z7Up04b9VYUondt8EPMqg7kTWgJ2g=="], - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.39.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/types": "8.39.0", "@typescript-eslint/typescript-estree": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg=="], + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.39.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.39.1", "@typescript-eslint/types": "8.39.1", "@typescript-eslint/typescript-estree": "8.39.1", "@typescript-eslint/visitor-keys": "8.39.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.39.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.39.0", "@typescript-eslint/types": "^8.39.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.39.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.39.1", "@typescript-eslint/types": "^8.39.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-8fZxek3ONTwBu9ptw5nCKqZOSkXshZB7uAxuFF0J/wTMkKydjXCzqqga7MlFMpHi9DoG4BadhmTkITBcg8Aybw=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.39.0", "", { "dependencies": { "@typescript-eslint/types": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0" } }, "sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.39.1", "", { "dependencies": { "@typescript-eslint/types": "8.39.1", "@typescript-eslint/visitor-keys": "8.39.1" } }, "sha512-RkBKGBrjgskFGWuyUGz/EtD8AF/GW49S21J8dvMzpJitOF1slLEbbHnNEtAHtnDAnx8qDEdRrULRnWVx27wGBw=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.39.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.39.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA=="], - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.39.0", "", { "dependencies": { "@typescript-eslint/types": "8.39.0", "@typescript-eslint/typescript-estree": "8.39.0", "@typescript-eslint/utils": "8.39.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.39.1", "", { "dependencies": { "@typescript-eslint/types": "8.39.1", "@typescript-eslint/typescript-estree": "8.39.1", "@typescript-eslint/utils": "8.39.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-gu9/ahyatyAdQbKeHnhT4R+y3YLtqqHyvkfDxaBYk97EcbfChSJXyaJnIL3ygUv7OuZatePHmQvuH5ru0lnVeA=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.39.1", "", {}, "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.39.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.39.0", "@typescript-eslint/tsconfig-utils": "8.39.0", "@typescript-eslint/types": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.39.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.39.1", "@typescript-eslint/tsconfig-utils": "8.39.1", "@typescript-eslint/types": "8.39.1", "@typescript-eslint/visitor-keys": "8.39.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-EKkpcPuIux48dddVDXyQBlKdeTPMmALqBUbEk38McWv0qVEZwOpVJBi7ugK5qVNgeuYjGNQxrrnoM/5+TI/BPw=="], - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.39.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/types": "8.39.0", "@typescript-eslint/typescript-estree": "8.39.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.39.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.39.1", "@typescript-eslint/types": "8.39.1", "@typescript-eslint/typescript-estree": "8.39.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-VF5tZ2XnUSTuiqZFXCZfZs1cgkdd3O/sSYmdo2EpSyDlC86UM/8YytTmKnehOW3TGAlivqTDT6bS87B/GQ/jyg=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.39.0", "", { "dependencies": { "@typescript-eslint/types": "8.39.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.39.1", "", { "dependencies": { "@typescript-eslint/types": "8.39.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-W8FQi6kEh2e8zVhQ0eeRnxdvIoOkAp/CPAahcNio6nO9dsIwb9b34z90KOlheoyuVf6LSOEdjlkxSkapNEc+4A=="], - "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20250806.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20250806.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20250806.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20250806.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20250806.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20250806.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20250806.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20250806.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-dQWOle1t2QJHiGK+ILB5SCz1Q6VfGtkrZybT4FPSaddkskYN1djY6voxza8hd8yl1Yw0PmBmbqk3E4vTKyibig=="], + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20250816.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20250816.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20250816.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20250816.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20250816.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20250816.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20250816.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20250816.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-du/e72VqzVXFQqbKuEc7W+W9pWvIgKg0SwydHxzvzQ6TiccBAP/Ar7FUBEuYkFGQ2rbo7pYLj/zkoUCy08QW5w=="], - "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20250806.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rRlWJEkaNCJmd5Ph4NQAJK4NMVwhWuycMKeGxRw8Lj68kNymZTVsNi/TDYN3I1InBj7Fg2kwzygessHHzZTb8A=="], + "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20250816.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JM+b5qXA1M9G/NFmytUatwEFQSKz1JQDZBsHCLxHbWaGazbg+yJPTzsxKfSz+DW72hyGTldiQqeIdJKwg3G5uQ=="], - "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20250806.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-n2RRV0+SHR6QnaTlJoTX6Q4M7T/P0GtWfOGiKa7QUzQFRQQNdZpTv6P2KAB38b/cfCfX7PRb6mhCWK9FMHwB3w=="], + "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20250816.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-jwhb6osHxniK+gv23uSjalfTN2XoMiF7X8eIslIRKQ6ICqxf5k8XtOJY0v2lf/t3HxIQQdG962kDVwiGaN3K6w=="], - "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20250806.1", "", { "os": "linux", "cpu": "arm" }, "sha512-uriaW4phv1E6YkGTacGq8YzdZ11F1lgH1kfRjwDpzNB+UDV4ONqihU0mN1y0JRHhlqqhtKhBL6UnSqd4mbu6zA=="], + "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20250816.1", "", { "os": "linux", "cpu": "arm" }, "sha512-syEtVN8E5oOlTOm7CrE3vgoVveBPRKvBbkfShqzwlmq1mw51MWunwO3yDNB3tk9GC1w1VoISoYpe8xm/hUKqIQ=="], - "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20250806.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-fwRhKF3t4OCp4ClfNrXIXwS5G+02AymnmgFGrhvnF0Wg5II8ReVVu9mvazVcfrTN9RtJo4xVofstSF2EbgQ0Sg=="], + "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20250816.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-e9YXa8QJ2kxBE/eIIci0n906crKxw+C9exAoWysjEsShIsXghIyP3BedMMVRhp2ZigjAPD6pa2ibE1R637C60g=="], - "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20250806.1", "", { "os": "linux", "cpu": "x64" }, "sha512-EJ5/obfzrDse9KYXzZBpwzdpPad7+y/R+atXApAekIdULHLjYZ/5j/tZ9UMEnMWkCmZaFK6JpfHOG1jOGy71nA=="], + "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20250816.1", "", { "os": "linux", "cpu": "x64" }, "sha512-C1pGpcbR2KwAacOQ9e0pAEZeOIZOZ7+GGxQjFQBYxnFdZfT/AvrCP8rKbZhWUx0ghntskl4BejqhGGC3kTc8Cg=="], - "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20250806.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-hHY/4xBsV9SWqb2nAmd9J9FQfsbte5Q4WMB2JVXSbjni0EUdDJmQgdmQ+V7v5teMaaTYhpnRrdsO95jPiR3JAA=="], + "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20250816.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-tHiD2c4/GQQeSl5kbnNMcjFx0JaC3blbKA9oPMH11hrio/eRnHVrvmatLe5Mo4KOuCS5EHgNUhUvhI43TD0lfw=="], - "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20250806.1", "", { "os": "win32", "cpu": "x64" }, "sha512-CFFcMz1CwZPL4TKaR10h/sZuRzGE0kLNfXq1zDDgsL1aO8gcOSDuVKrYDdwYGdedLUCINSort7kyv9nIFUKSqQ=="], + "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20250816.1", "", { "os": "win32", "cpu": "x64" }, "sha512-4Gm8x1fjnPU441faBu9Mgf9xUWC/DTetulu1bXNcdcrmSkRCFNiIQFtM/IBz47ghDaec4+XiHlrYxkzcaN/avw=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], @@ -1293,7 +1297,7 @@ "attr-accept": ["attr-accept@2.2.5", "", {}, "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ=="], - "autumn-js": ["autumn-js@0.1.8", "", { "dependencies": { "rou3": "^0.6.1", "swr": "^2.3.3", "zod": "^3.24.1" }, "peerDependencies": { "better-auth": "^1.2.12", "better-call": "^1.0.12" }, "optionalPeers": ["better-auth", "better-call"] }, "sha512-tayOSj4hFYUvfaIkmjwDyMMnKZ4duTMzuLCOXBT1HZSgO/3guAqEmaz3OQupdw/JbhpnsOEVsQfrFV2dFUU2Mw=="], + "autumn-js": ["autumn-js@0.1.12", "", { "dependencies": { "rou3": "^0.6.1", "swr": "^2.3.3", "zod": "^4.0.0" }, "peerDependencies": { "better-auth": "^1.2.12", "better-call": "^1.0.12" }, "optionalPeers": ["better-auth", "better-call"] }, "sha512-FvWM5txsOjal+GHmMlC+pA/+bUQQYNDXQOvwA620UzD3oxpU/25SCDeJDj+Fyzn6pqNdLjeUaUQ/XNPPks23Ug=="], "axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="], @@ -1301,15 +1305,15 @@ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "bare-events": ["bare-events@2.6.0", "", {}, "sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg=="], + "bare-events": ["bare-events@2.6.1", "", {}, "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g=="], - "bare-fs": ["bare-fs@4.1.6", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-25RsLF33BqooOEFNdMcEhMpJy8EoR88zSMrnOQOaM3USnOK2VmaJ1uaQEwPA6AQjrv1lXChScosN6CzbwbO9OQ=="], + "bare-fs": ["bare-fs@4.2.0", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-oRfrw7gwwBVAWx9S5zPMo2iiOjxyiZE12DmblmMQREgcogbNO0AFaZ+QBxxkEXiPspcpvO/Qtqn8LabUx4uYXg=="], "bare-os": ["bare-os@3.6.1", "", {}, "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g=="], "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], - "bare-stream": ["bare-stream@2.6.5", "", { "dependencies": { "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-buffer", "bare-events"] }, "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA=="], + "bare-stream": ["bare-stream@2.7.0", "", { "dependencies": { "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-buffer", "bare-events"] }, "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A=="], "base-convert-int-array": ["base-convert-int-array@1.0.1", "", {}, "sha512-NWqzaoXx8L/SS32R+WmKqnQkVXVYl2PwNJ68QV3RAlRRL1uV+yxJT66abXI1cAvqCXQTyXr7/9NN4Af90/zDVw=="], @@ -1319,7 +1323,7 @@ "basic-ftp": ["basic-ftp@5.0.5", "", {}, "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg=="], - "better-auth": ["better-auth@1.3.4", "", { "dependencies": { "@better-auth/utils": "0.2.5", "@better-fetch/fetch": "^1.1.18", "@noble/ciphers": "^0.6.0", "@noble/hashes": "^1.8.0", "@simplewebauthn/browser": "^13.0.0", "@simplewebauthn/server": "^13.0.0", "better-call": "^1.0.12", "defu": "^6.1.4", "jose": "^5.9.6", "kysely": "^0.28.1", "nanostores": "^0.11.3", "zod": "^4.0.5" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-JbZYam6Cs3Eu5CSoMK120zSshfaKvrCftSo/+v7524H1RvhryQ7UtMbzagBcXj0Digjj8hZtVkkR4tTZD/wK2g=="], + "better-auth": ["better-auth@1.3.6", "", { "dependencies": { "@better-auth/utils": "0.2.6", "@better-fetch/fetch": "^1.1.18", "@noble/ciphers": "^0.6.0", "@noble/hashes": "^1.8.0", "@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/server": "^13.1.2", "better-call": "^1.0.13", "defu": "^6.1.4", "jose": "^5.10.0", "kysely": "^0.28.5", "nanostores": "^0.11.4" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-zjwbz9GpgGt3LuvJ8ZXfQeowSRpzdGojVvkhxvXjhCLwGOaOrZmFiNdEVyIKWTraN4oBtgNimcxUIQTGs6OKYg=="], "better-call": ["better-call@1.0.13", "", { "dependencies": { "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-auqdP9lnNOli9tKpZIiv0nEIwmmyaD/RotM3Mucql+Ef88etoZi/t7Ph5LjlmZt/hiSahhNTt6YVnx6++rziXA=="], @@ -1337,7 +1341,7 @@ "browser-stdout": ["browser-stdout@1.3.1", "", {}, "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="], - "browserslist": ["browserslist@4.25.1", "", { "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw=="], + "browserslist": ["browserslist@4.25.2", "", { "dependencies": { "caniuse-lite": "^1.0.30001733", "electron-to-chromium": "^1.5.199", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA=="], "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], @@ -1345,9 +1349,9 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "bullmq": ["bullmq@5.56.9", "", { "dependencies": { "cron-parser": "^4.9.0", "ioredis": "^5.4.1", "msgpackr": "^1.11.2", "node-abort-controller": "^3.1.1", "semver": "^7.5.4", "tslib": "^2.0.0", "uuid": "^9.0.0" } }, "sha512-SL7OZG0x9sh/PC6ZVKqibSmPsbjViBaiFAyr3ujJRxb6nlZefb1hU0biJuvfI8/hQa4HtEG9sCHRMiz905B2eg=="], + "bullmq": ["bullmq@5.58.0", "", { "dependencies": { "cron-parser": "^4.9.0", "ioredis": "^5.4.1", "msgpackr": "^1.11.2", "node-abort-controller": "^3.1.1", "semver": "^7.5.4", "tslib": "^2.0.0", "uuid": "^9.0.0" } }, "sha512-WIjvoSQ9jprId2gAZaPMQu3jaAkRCN8Wjj/pR39knwjULB7asB6XoSTqvnSbOsfyHMKln8el0MRvRJVY9VdmFA=="], - "bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="], + "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], @@ -1359,7 +1363,7 @@ "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001731", "", {}, "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg=="], + "caniuse-lite": ["caniuse-lite@1.0.30001735", "", {}, "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], @@ -1373,7 +1377,7 @@ "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], - "chardet": ["chardet@0.7.0", "", {}, "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="], + "chardet": ["chardet@2.1.0", "", {}, "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA=="], "charset": ["charset@1.0.1", "", {}, "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg=="], @@ -1383,7 +1387,7 @@ "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], - "chromium-bidi": ["chromium-bidi@7.2.0", "", { "dependencies": { "mitt": "^3.0.1", "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-gREyhyBstermK+0RbcJLbFhcQctg92AGgDe/h/taMJEOLRdtSswBAO9KmvltFSQWgM2LrwWu5SIuEUbdm3JsyQ=="], + "chromium-bidi": ["chromium-bidi@7.3.1", "", { "dependencies": { "mitt": "^3.0.1", "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-i+BMGluhZZc4Jic9L1aHJBTfaopxmCqQxGklyMcqFx4fvF3nI4BJ3bCe1ad474nvYRIo/ZN/VrdA4eOaRZua4Q=="], "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], @@ -1575,7 +1579,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.197", "", {}, "sha512-m1xWB3g7vJ6asIFz+2pBUbq3uGmfmln1M9SSvBe4QIFWYrRHylP73zL/3nMjDmwz8V+1xAXQDfBd6+HPW0WvDQ=="], + "electron-to-chromium": ["electron-to-chromium@1.5.203", "", {}, "sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g=="], "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], @@ -1599,11 +1603,11 @@ "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], - "es-toolkit": ["es-toolkit@1.39.8", "", {}, "sha512-A8QO9TfF+rltS8BXpdu8OS+rpGgEdnRhqIVxO/ZmNvnXBYgOdSsxukT55ELyP94gZIntWJ+Li9QRrT2u1Kitpg=="], + "es-toolkit": ["es-toolkit@1.39.9", "", {}, "sha512-9OtbkZmTA2Qc9groyA1PUNeb6knVTkvB2RSdr/LcJXDL8IdEakaxwXLHXa7VX/Wj0GmdMJPR3WhnPGhiP3E+qg=="], "es6-promise": ["es6-promise@4.2.8", "", {}, "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="], - "esbuild": ["esbuild@0.25.8", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.8", "@esbuild/android-arm": "0.25.8", "@esbuild/android-arm64": "0.25.8", "@esbuild/android-x64": "0.25.8", "@esbuild/darwin-arm64": "0.25.8", "@esbuild/darwin-x64": "0.25.8", "@esbuild/freebsd-arm64": "0.25.8", "@esbuild/freebsd-x64": "0.25.8", "@esbuild/linux-arm": "0.25.8", "@esbuild/linux-arm64": "0.25.8", "@esbuild/linux-ia32": "0.25.8", "@esbuild/linux-loong64": "0.25.8", "@esbuild/linux-mips64el": "0.25.8", "@esbuild/linux-ppc64": "0.25.8", "@esbuild/linux-riscv64": "0.25.8", "@esbuild/linux-s390x": "0.25.8", "@esbuild/linux-x64": "0.25.8", "@esbuild/netbsd-arm64": "0.25.8", "@esbuild/netbsd-x64": "0.25.8", "@esbuild/openbsd-arm64": "0.25.8", "@esbuild/openbsd-x64": "0.25.8", "@esbuild/openharmony-arm64": "0.25.8", "@esbuild/sunos-x64": "0.25.8", "@esbuild/win32-arm64": "0.25.8", "@esbuild/win32-ia32": "0.25.8", "@esbuild/win32-x64": "0.25.8" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q=="], + "esbuild": ["esbuild@0.25.9", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.9", "@esbuild/android-arm": "0.25.9", "@esbuild/android-arm64": "0.25.9", "@esbuild/android-x64": "0.25.9", "@esbuild/darwin-arm64": "0.25.9", "@esbuild/darwin-x64": "0.25.9", "@esbuild/freebsd-arm64": "0.25.9", "@esbuild/freebsd-x64": "0.25.9", "@esbuild/linux-arm": "0.25.9", "@esbuild/linux-arm64": "0.25.9", "@esbuild/linux-ia32": "0.25.9", "@esbuild/linux-loong64": "0.25.9", "@esbuild/linux-mips64el": "0.25.9", "@esbuild/linux-ppc64": "0.25.9", "@esbuild/linux-riscv64": "0.25.9", "@esbuild/linux-s390x": "0.25.9", "@esbuild/linux-x64": "0.25.9", "@esbuild/netbsd-arm64": "0.25.9", "@esbuild/netbsd-x64": "0.25.9", "@esbuild/openbsd-arm64": "0.25.9", "@esbuild/openbsd-x64": "0.25.9", "@esbuild/openharmony-arm64": "0.25.9", "@esbuild/sunos-x64": "0.25.9", "@esbuild/win32-arm64": "0.25.9", "@esbuild/win32-ia32": "0.25.9", "@esbuild/win32-x64": "0.25.9" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g=="], "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], @@ -1615,7 +1619,7 @@ "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="], - "eslint": ["eslint@9.32.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.32.0", "@eslint/plugin-kit": "^0.3.4", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg=="], + "eslint": ["eslint@9.33.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.33.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA=="], "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="], @@ -1651,8 +1655,6 @@ "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], - "external-editor": ["external-editor@3.1.0", "", { "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew=="], - "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="], "fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="], @@ -1677,7 +1679,7 @@ "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], - "fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="], @@ -1833,13 +1835,13 @@ "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], - "inquirer": ["inquirer@12.9.0", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/prompts": "^7.8.0", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "mute-stream": "^2.0.0", "run-async": "^4.0.5", "rxjs": "^7.8.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-LlFVmvWVCun7uEgPB3vups9NzBrjJn48kRNtFGw3xU1H5UXExTEz/oF1JGLaB0fvlkUB+W6JfgLcSEaSdH7RPA=="], + "inquirer": ["inquirer@12.9.2", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/prompts": "^7.8.2", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "mute-stream": "^2.0.0", "run-async": "^4.0.5", "rxjs": "^7.8.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-XPukbomHpZc3GAajQdAcuqa5NCIFhUcLMcXXSpJLM2RW/u/5JHLxjLF206GNTJARib8XBBRqyMbaNrDzXROdoA=="], "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], "ioredis": ["ioredis@5.7.0", "", { "dependencies": { "@ioredis/commands": "^1.3.0", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g=="], - "ip-address": ["ip-address@9.0.5", "", { "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" } }, "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g=="], + "ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="], "ip-regex": ["ip-regex@5.0.0", "", {}, "sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw=="], @@ -1879,8 +1881,6 @@ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "isows": ["isows@1.0.7", "", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "jiti": ["jiti@2.5.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w=="], @@ -1895,8 +1895,6 @@ "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], - "jsbn": ["jsbn@1.1.0", "", {}, "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="], - "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], @@ -1947,7 +1945,7 @@ "ksuid": ["ksuid@3.0.0", "", { "dependencies": { "base-convert-int-array": "^1.0.1" } }, "sha512-81CkBGn/06ZVAjGvFZi6fVG8VcPeMH0JpJ4V1Z9VwrMMaGIeAjY4jrVdrIcxhL9I2ZUU6t5uiyswcmkk+KZegA=="], - "kysely": ["kysely@0.28.4", "", {}, "sha512-pfQj8/Bo3KSzC1HIZB5MeeYRWcDmx1ZZv8H25LsyeygqXE+gfsbUAgPT1GSYZFctB1cdOVlv+OifuCls2mQSnw=="], + "kysely": ["kysely@0.28.5", "", {}, "sha512-rlB0I/c6FBDWPcQoDtkxi9zIvpmnV5xoIalfCMSMCa7nuA6VGA3F54TW9mEgX4DVf10sXAWCF5fDbamI/5ZpKA=="], "leac": ["leac@0.6.0", "", {}, "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg=="], @@ -2139,8 +2137,6 @@ "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="], - "os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="], - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], @@ -2195,7 +2191,7 @@ "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "pino": ["pino@9.7.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg=="], + "pino": ["pino@9.9.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-zxsRIQG9HzG+jEljmvmZupOMDUQ0Jpj0yAgE28jQvvrdYTlEaiGwelJpdndMl/MBuRr70heIj83QyqJUWaU8mQ=="], "pino-abstract-transport": ["pino-abstract-transport@1.2.0", "", { "dependencies": { "readable-stream": "^4.0.0", "split2": "^4.0.0" } }, "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q=="], @@ -2217,7 +2213,7 @@ "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], - "posthog-js": ["posthog-js@1.258.6", "", { "dependencies": { "core-js": "^3.38.1", "fflate": "^0.4.8", "preact": "^10.19.3", "web-vitals": "^4.2.4" }, "peerDependencies": { "@rrweb/types": "2.0.0-alpha.17", "rrweb-snapshot": "2.0.0-alpha.17" }, "optionalPeers": ["@rrweb/types", "rrweb-snapshot"] }, "sha512-vL5AGG+rOoRg3LGquMfBPO55jD4bGl0CiV44SHdHAoBnOVDDAqxczRGDqMdxor+VLx3/ofTFOJ2FNprfAHp70Q=="], + "posthog-js": ["posthog-js@1.260.1", "", { "dependencies": { "core-js": "^3.38.1", "fflate": "^0.4.8", "preact": "^10.19.3", "web-vitals": "^4.2.4" }, "peerDependencies": { "@rrweb/types": "2.0.0-alpha.17", "rrweb-snapshot": "2.0.0-alpha.17" }, "optionalPeers": ["@rrweb/types", "rrweb-snapshot"] }, "sha512-DD8ZSRpdScacMqtqUIvMFme8lmOWkOvExG8VvjONE7Cm3xpRH5xXpfrwMJE4bayTGWKMx4ij6SfphK6dm/o2ug=="], "posthog-node": ["posthog-node@4.18.0", "", { "dependencies": { "axios": "^1.8.2" } }, "sha512-XROs1h+DNatgKh/AlIlCtDxWzwrKdYDb2mOs58n4yN8BkGN9ewqeQwG5ApS4/IzwCb7HPttUkOVulkYatd2PIw=="], @@ -2241,7 +2237,7 @@ "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], - "protobufjs": ["protobufjs@7.5.3", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw=="], + "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="], "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], @@ -2255,7 +2251,7 @@ "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "puppeteer-core": ["puppeteer-core@24.16.0", "", { "dependencies": { "@puppeteer/browsers": "2.10.6", "chromium-bidi": "7.2.0", "debug": "^4.4.1", "devtools-protocol": "0.0.1475386", "typed-query-selector": "^2.12.0", "ws": "^8.18.3" } }, "sha512-tZ0tJiOYaDGTRzzr2giDpf8O/55JsoqkrafS1Xu4H6S8oP4eeL6RbZzY9OzjShSf5EQvx/zAc55QKpDqzXos/Q=="], + "puppeteer-core": ["puppeteer-core@24.16.2", "", { "dependencies": { "@puppeteer/browsers": "2.10.6", "chromium-bidi": "7.3.1", "debug": "^4.4.1", "devtools-protocol": "0.0.1475386", "typed-query-selector": "^2.12.0", "ws": "^8.18.3" } }, "sha512-areKSSQzpoHa5nCk3uD/o504yjrW5ws0N6jZfdFZ3a4H+Q7NBgvuDydjN5P87jN4Rj+eIpLcK3ELOThTtYuuxg=="], "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], @@ -2291,7 +2287,7 @@ "react-email": ["react-email@4.0.16", "", { "dependencies": { "@babel/parser": "^7.27.0", "@babel/traverse": "^7.27.0", "chalk": "^5.0.0", "chokidar": "^4.0.3", "commander": "^13.0.0", "debounce": "^2.0.0", "esbuild": "^0.25.0", "glob": "^11.0.0", "log-symbols": "^7.0.0", "mime-types": "^3.0.0", "next": "^15.3.1", "normalize-path": "^3.0.0", "ora": "^8.0.0", "socket.io": "^4.8.1" }, "bin": { "email": "dist/cli/index.mjs" } }, "sha512-auhFU+nQxAkKkP6lQhPyGsa9exwfUEzp2BwZnjHokCwphZlg30tu4t1LgdKRwGPYsi7XNGy6asbVLAUhOVpzzg=="], - "react-hot-toast": ["react-hot-toast@2.5.2", "", { "dependencies": { "csstype": "^3.1.3", "goober": "^2.1.16" }, "peerDependencies": { "react": ">=16", "react-dom": ">=16" } }, "sha512-Tun3BbCxzmXXM7C+NI4qiv6lT0uwGh4oAfeJyNOjYUejTsm35mK9iCaYLGv8cBz9L5YxZLx/2ii7zsIwPtPUdw=="], + "react-hot-toast": ["react-hot-toast@2.6.0", "", { "dependencies": { "csstype": "^3.1.3", "goober": "^2.1.16" }, "peerDependencies": { "react": ">=16", "react-dom": ">=16" } }, "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg=="], "react-hotkeys-hook": ["react-hotkeys-hook@4.6.2", "", { "peerDependencies": { "react": ">=16.8.1", "react-dom": ">=16.8.1" } }, "sha512-FmP+ZriY3EG59Ug/lxNfrObCnW9xQShgk7Nb83+CkpfkcCpfS95ydv+E9JuXA5cp8KtskU7LGlIARpkc92X22Q=="], @@ -2309,9 +2305,9 @@ "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], - "react-router": ["react-router@7.7.1", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA=="], + "react-router": ["react-router@7.8.1", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-5cy/M8DHcG51/KUIka1nfZ2QeylS4PJRs6TT8I4PF5axVsI5JUxp0hC0NZ/AEEj8Vw7xsEoD7L/6FY+zoYaOGA=="], - "react-router-dom": ["react-router-dom@7.7.1", "", { "dependencies": { "react-router": "7.7.1" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ=="], + "react-router-dom": ["react-router-dom@7.8.1", "", { "dependencies": { "react-router": "7.8.1" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-NkgBCF3sVgCiAWIlSt89GR2PLaksMpoo3HDCorpRfnCEfdtRPLiuTf+CNXvqZMI5SJLZCLpVCvcZrTdtGW64xQ=="], "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], @@ -2357,7 +2353,7 @@ "rou3": ["rou3@0.6.3", "", {}, "sha512-1HSG1ENTj7Kkm5muMnXuzzfdDOf7CFnbSYFA+H3Fp/rB9lOCxCPgy1jlZxTKyFoC5jJay8Mmc+VbPLYRjzYLrA=="], - "run-async": ["run-async@4.0.5", "", {}, "sha512-oN9GTgxUNDBumHTTDmQ8dep6VIJbgj9S3dPP+9XylVLIK4xB9XTXtKWROd5pnhdXR9k0EgO1JRcNh0T+Ny2FsA=="], + "run-async": ["run-async@4.0.6", "", {}, "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], @@ -2425,7 +2421,7 @@ "socket.io-parser": ["socket.io-parser@4.2.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" } }, "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew=="], - "socks": ["socks@2.8.6", "", { "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA=="], + "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], @@ -2443,8 +2439,6 @@ "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], - "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], - "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], "standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="], @@ -2487,13 +2481,11 @@ "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "svix": ["svix@1.70.1", "", { "dependencies": { "@stablelib/base64": "^1.0.0", "@types/node": "^22.7.5", "es6-promise": "^4.2.8", "fast-sha256": "^1.3.0", "svix-fetch": "^3.0.0", "url-parse": "^1.5.10", "uuid": "^10.0.0" } }, "sha512-UDO8VBNyfZcqRjQQLanrOanGK+nCaMhBT7LJyXQBhPLEUcoDzRUhKujFdivl2OrleUVNknmuuz7CnYZ+4Axugg=="], - - "svix-fetch": ["svix-fetch@3.0.0", "", { "dependencies": { "node-fetch": "^2.6.1", "whatwg-fetch": "^3.4.1" } }, "sha512-rcADxEFhSqHbraZIsjyZNh4TF6V+koloX1OzZ+AQuObX9mZ2LIMhm1buZeuc5BIZPftZpJCMBsSiBaeszo9tRw=="], + "svix": ["svix@1.73.0", "", { "dependencies": { "@stablelib/base64": "^1.0.0", "@types/node": "^22.7.5", "es6-promise": "^4.2.8", "fast-sha256": "^1.3.0", "url-parse": "^1.5.10", "uuid": "^10.0.0" } }, "sha512-EqaQcuJezFxJBWvtjfRhhDtVYcrYdzLiVqc2Naw3aGwd3FrCzqLUwLHEWo8LE2MoPEUGm/2xSt8b9W7NLQr25w=="], "svix-react": ["svix-react@1.13.5", "", { "dependencies": { "iframe-resizer-react": "^1.1.0" }, "peerDependencies": { "react": ">=16", "react-dom": ">=16", "svix": ">=1.26.0" } }, "sha512-2UnpYFvr5yCZuvpaYA4F1A/zv8NGyXHas8xBeR6ozJ1MOLKvdf0anqNE3ZTyUr+ngr7Sd3tcQgiJt1vpFU35xQ=="], - "swr": ["swr@2.3.4", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg=="], + "swr": ["swr@2.3.6", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw=="], "symbol-observable": ["symbol-observable@1.2.0", "", {}, "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="], @@ -2501,7 +2493,7 @@ "tailwind-scrollbar-hide": ["tailwind-scrollbar-hide@4.0.0", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || >= 4.0.0 || >= 4.0.0-beta.8 || >= 4.0.0-alpha.20" } }, "sha512-gobtvVcThB2Dxhy0EeYSS1RKQJ5baDFkamkhwBvzvevwX6L4XQfpZ3me9s25Ss1ecFVT5jPYJ50n+7xTBJG9WQ=="], - "tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="], + "tailwindcss": ["tailwindcss@4.1.12", "", {}, "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA=="], "tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="], @@ -2529,8 +2521,6 @@ "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="], - "tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], @@ -2555,7 +2545,7 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tsx": ["tsx@4.20.3", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ=="], + "tsx": ["tsx@4.20.4", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg=="], "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], @@ -2567,7 +2557,7 @@ "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], - "typescript-eslint": ["typescript-eslint@8.39.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.39.0", "@typescript-eslint/parser": "8.39.0", "@typescript-eslint/typescript-estree": "8.39.0", "@typescript-eslint/utils": "8.39.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-lH8FvtdtzcHJCkMOKnN73LIn6SLTpoojgJqDAxPm1jCR14eWSGPX8ul/gggBdPMk/d5+u9V854vTYQ8T5jF/1Q=="], + "typescript-eslint": ["typescript-eslint@8.39.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.39.1", "@typescript-eslint/parser": "8.39.1", "@typescript-eslint/typescript-estree": "8.39.1", "@typescript-eslint/utils": "8.39.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-GDUv6/NDYngUlNvwaHM1RamYftxf782IyEDbdj3SeaIHHv8fNQVRC++fITT7kUJV/5rIA/tkoRSSskt6osEfqg=="], "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], @@ -2633,8 +2623,6 @@ "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], - "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], - "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], @@ -2685,13 +2673,13 @@ "@ai-sdk/provider-utils/secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], - "@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], + "@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], - "@anthropic-ai/sdk/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="], + "@anthropic-ai/sdk/@types/node": ["@types/node@18.19.123", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg=="], - "@autumn/server/@types/node": ["@types/node@22.17.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ=="], + "@autumn/server/@types/node": ["@types/node@22.17.2", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w=="], - "@autumn/vite/@types/node": ["@types/node@22.17.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ=="], + "@autumn/vite/@types/node": ["@types/node@22.17.2", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w=="], "@autumn/vite/date-fns": ["date-fns@3.6.0", "", {}, "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww=="], @@ -2703,7 +2691,7 @@ "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], + "@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], @@ -2711,12 +2699,12 @@ "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@better-auth/stripe/zod": ["zod@4.0.15", "", {}, "sha512-2IVHb9h4Mt6+UXkyMs0XbfICUh1eUrlJJAOupBHUhLRnKkruawyDddYRCs0Eizt900ntIMk9/4RksYl+FgSpcQ=="], - - "@browserbasehq/sdk/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="], + "@browserbasehq/sdk/@types/node": ["@types/node@18.19.123", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg=="], "@clerk/backend/cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + "@clerk/shared/swr": ["swr@2.3.4", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg=="], + "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], @@ -2751,11 +2739,15 @@ "@hyperdx/node-opentelemetry/ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + "@inquirer/external-editor/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], + "@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], + + "@jridgewell/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], "@opentelemetry/auto-instrumentations-node/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], @@ -3031,7 +3023,7 @@ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" }, "bundled": true }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], - "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="], "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -3041,7 +3033,7 @@ "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "better-auth/zod": ["zod@4.0.15", "", {}, "sha512-2IVHb9h4Mt6+UXkyMs0XbfICUh1eUrlJJAOupBHUhLRnKkruawyDddYRCs0Eizt900ntIMk9/4RksYl+FgSpcQ=="], + "autumn-js/zod": ["zod@4.0.17", "", {}, "sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ=="], "better-call/rou3": ["rou3@0.5.1", "", {}, "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ=="], @@ -3057,7 +3049,7 @@ "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "cloudflare/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="], + "cloudflare/@types/node": ["@types/node@18.19.123", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg=="], "concurrently/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -3093,7 +3085,7 @@ "nodemon/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], - "openai/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="], + "openai/@types/node": ["@types/node@18.19.123", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg=="], "ora/is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], @@ -3105,7 +3097,7 @@ "pino-pretty/pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], - "pino-pretty/strip-json-comments": ["strip-json-comments@5.0.2", "", {}, "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g=="], + "pino-pretty/strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], "postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], @@ -3121,7 +3113,7 @@ "react-router/cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], - "recaseai/@types/node": ["@types/node@22.17.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ=="], + "recaseai/@types/node": ["@types/node@22.17.2", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w=="], "recaseai/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], @@ -3151,7 +3143,7 @@ "superagent/qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], - "svix/@types/node": ["@types/node@22.17.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ=="], + "svix/@types/node": ["@types/node@22.17.2", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w=="], "svix/uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="], @@ -3467,8 +3459,6 @@ "@sentry/node/@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="], - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="], - "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], diff --git a/server/run.sh b/server/run.sh index 48a2ac48e..891ab4890 100755 --- a/server/run.sh +++ b/server/run.sh @@ -27,14 +27,3 @@ else NODE_ENV=development bun "$filename" fi - -# # If filename ends with .sh, then run it -# if [ "${filename##*.}" = "sh" ]; then -# ./$filename -# else if [ "${filename##*.}" = "ts" ]; then -# npx tsx $filename -# else -# echo "Invalid file extension" -# fi - -# # npm run test \ No newline at end of file diff --git a/server/shell/g1.sh b/server/shell/g1.sh index d55031071..83e778557 100755 --- a/server/shell/g1.sh +++ b/server/shell/g1.sh @@ -5,18 +5,19 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/config.sh" # If contains setup then run $MOCHA_SETUP -if [[ "$2" == *"setup"* ]]; then -MOCHA_PARALLEL=true $MOCHA_SETUP +if [[ "$1" == *"setup"* ]]; then + MOCHA_PARALLEL=true $MOCHA_SETUP fi $MOCHA_CMD \ 'tests/attach/basic/*.ts' \ 'tests/attach/upgrade/*.ts' \ 'tests/attach/downgrade/*.ts' \ -'tests/attach/checkout/*.ts' +'tests/attach/addOn/*.ts' $MOCHA_CMD \ +'tests/attach/checkout/*.ts' \ 'tests/attach/entities/*.ts' \ -'tests/attach/free/*.ts' +'tests/attach/free/*.ts'\ # 'tests/attach/basic/basic2.ts' \ \ No newline at end of file diff --git a/server/shell/g3.sh b/server/shell/g3.sh index 60aa554da..97d2db32e 100755 --- a/server/shell/g3.sh +++ b/server/shell/g3.sh @@ -17,15 +17,15 @@ $MOCHA_CMD 'tests/contUse/track/*.ts' $MOCHA_CMD 'tests/contUse/roles/*.ts' -# G4 -$MOCHA_CMD 'tests/advanced/multiFeature/*.ts' \ - 'tests/advanced/coupons/*.ts' \ - 'tests/attach/updateQuantity/*.ts' \ - 'tests/advanced/referrals/*.ts' \ - 'tests/advanced/rollovers/*.ts' \ - 'tests/advanced/customInterval/*.ts' +# # G4 +# $MOCHA_CMD 'tests/advanced/multiFeature/*.ts' \ +# 'tests/advanced/coupons/*.ts' \ +# 'tests/attach/updateQuantity/*.ts' \ +# 'tests/advanced/referrals/*.ts' \ +# 'tests/advanced/rollovers/*.ts' \ +# 'tests/advanced/customInterval/*.ts' -$MOCHA_CMD 'tests/attach/multiProduct/*.ts' \ - 'tests/advanced/usageLimit/*.ts' +# $MOCHA_CMD 'tests/attach/multiProduct/*.ts' \ +# 'tests/advanced/usageLimit/*.ts' -$MOCHA_CMD 'tests/advanced/usage/*.ts' \ No newline at end of file +# $MOCHA_CMD 'tests/advanced/usage/*.ts' \ No newline at end of file diff --git a/server/src/external/autumn/autumnCli.ts b/server/src/external/autumn/autumnCli.ts index 0557c6ad2..eb2510e2d 100644 --- a/server/src/external/autumn/autumnCli.ts +++ b/server/src/external/autumn/autumnCli.ts @@ -170,7 +170,9 @@ export class AutumnInt { return data; } - async checkout(params: CheckoutParams) { + async checkout( + params: CheckoutParams & { invoice?: boolean; force_checkout?: boolean } + ) { // const data = await this.post(`/attach`, { // customer_id: customerId, // product_id: productId, diff --git a/server/src/external/stripe/priceToStripeItem/priceToUsageInAdvance.ts b/server/src/external/stripe/priceToStripeItem/priceToUsageInAdvance.ts index d4f4db7f3..2794f4103 100644 --- a/server/src/external/stripe/priceToStripeItem/priceToUsageInAdvance.ts +++ b/server/src/external/stripe/priceToStripeItem/priceToUsageInAdvance.ts @@ -1,5 +1,5 @@ import { getPriceForOverage } from "@/internal/products/prices/priceUtils.js"; -import { nullish } from "@/utils/genUtils.js"; +import { notNullish, nullish } from "@/utils/genUtils.js"; import { FeatureOptions, Organization, UsagePriceConfig } from "@autumn/shared"; import { EntitlementWithFeature } from "@autumn/shared"; import { Price } from "@autumn/shared"; @@ -29,7 +29,7 @@ export const priceToOneOffAndTiered = ({ const amount = getPriceForOverage(price, overage); if (!config.stripe_product_id) { console.log( - `WARNING: One off & tiered in advance price has no stripe product id: ${price.id}, ${relatedEnt.feature.name}`, + `WARNING: One off & tiered in advance price has no stripe product id: ${price.id}, ${relatedEnt.feature.name}` ); } return { @@ -61,7 +61,7 @@ export const priceToUsageInAdvance = ({ let finalQuantity = optionsQuantity; // 1. If adjustable quantity is set, use that, else if quantity is undefined, adjustable is true, else false - let adjustable = !nullish(options?.adjustable_quantity) + let adjustable = notNullish(options?.adjustable_quantity) ? options!.adjustable_quantity : nullish(optionsQuantity) ? true diff --git a/server/src/external/stripe/stripeOnboardingUtils.ts b/server/src/external/stripe/stripeOnboardingUtils.ts index 207b864fd..351afbe3d 100644 --- a/server/src/external/stripe/stripeOnboardingUtils.ts +++ b/server/src/external/stripe/stripeOnboardingUtils.ts @@ -42,6 +42,7 @@ export const createWebhookEndpoint = async ( "invoice.upcoming", "invoice.created", "invoice.finalized", + "invoice.updated", "subscription_schedule.canceled", "customer.discount.deleted", ], diff --git a/server/src/external/stripe/stripeSubUtils/createStripeSub.ts b/server/src/external/stripe/stripeSubUtils/createStripeSub.ts index 74792160f..c2b15d6f4 100644 --- a/server/src/external/stripe/stripeSubUtils/createStripeSub.ts +++ b/server/src/external/stripe/stripeSubUtils/createStripeSub.ts @@ -11,7 +11,11 @@ import { import Stripe from "stripe"; import { getCusPaymentMethod } from "../stripeCusUtils.js"; import { SubService } from "@/internal/subscriptions/SubService.js"; -import { formatUnixToDateTime, generateId, notNullish } from "@/utils/genUtils.js"; +import { + formatUnixToDateTime, + generateId, + notNullish, +} from "@/utils/genUtils.js"; import { ItemSet } from "@/utils/models/ItemSet.js"; import { DrizzleCli } from "@/db/initDrizzle.js"; import { getAlignedIntervalUnix } from "@/internal/products/prices/billingIntervalUtils.js"; @@ -46,7 +50,8 @@ export const createStripeSub = async ({ let paymentMethod = await getCusPaymentMethod({ stripeCli, stripeId: customer.processor.id, - errorIfNone: !invoiceOnly && (notNullish(freeTrial) && freeTrial?.card_required), // throw error if no payment method and invoiceOnly is false OR if its a free trial and card is required but no payment method + errorIfNone: + !invoiceOnly && notNullish(freeTrial) && freeTrial?.card_required, // throw error if no payment method and invoiceOnly is false OR if its a free trial and card is required but no payment method }); let paymentMethodData = {}; @@ -85,7 +90,11 @@ export const createStripeSub = async ({ trial_end: freeTrialToStripeTimestamp({ freeTrial, now }), payment_behavior: "error_if_incomplete", add_invoice_items: invoiceItems, - collection_method: freeTrial ? undefined : invoiceOnly ? "send_invoice" : "charge_automatically", + collection_method: freeTrial + ? undefined + : invoiceOnly + ? "send_invoice" + : "charge_automatically", days_until_due: freeTrial ? undefined : invoiceOnly ? 30 : undefined, billing_cycle_anchor: billingCycleAnchorUnix ? Math.floor(billingCycleAnchorUnix / 1000) @@ -93,16 +102,24 @@ export const createStripeSub = async ({ coupon: reward ? reward.id : undefined, - trial_settings: freeTrial && !freeTrial.card_required ? { - end_behavior: { - missing_payment_method: "cancel", - }, - } : undefined, + trial_settings: + freeTrial && !freeTrial.card_required + ? { + end_behavior: { + missing_payment_method: "cancel", + }, + } + : undefined, + expand: ["latest_invoice"], }); - if (invoiceOnly && finalizeInvoice) { - await stripeCli.invoices.finalizeInvoice( - subscription.latest_invoice as string + if ( + invoiceOnly && + finalizeInvoice && + (subscription.latest_invoice as Stripe.Invoice).status === "draft" + ) { + subscription.latest_invoice = await stripeCli.invoices.finalizeInvoice( + (subscription.latest_invoice as Stripe.Invoice).id ); } diff --git a/server/src/external/stripe/stripeWebhooks.ts b/server/src/external/stripe/stripeWebhooks.ts index 7a755dd70..2ec239a7f 100644 --- a/server/src/external/stripe/stripeWebhooks.ts +++ b/server/src/external/stripe/stripeWebhooks.ts @@ -21,6 +21,7 @@ import { createStripeCli } from "./utils.js"; import { deleteCusCache } from "@/internal/customers/cusCache/updateCachedCus.js"; import { CusService } from "@/internal/customers/CusService.js"; import { DrizzleCli } from "@/db/initDrizzle.js"; +import { handleInvoiceUpdated } from "./webhookHandlers/handleInvoiceUpdated.js"; export const stripeWebhookRouter: Router = express.Router(); @@ -183,6 +184,15 @@ stripeWebhookRouter.post( }); break; + case "invoice.updated": + await handleInvoiceUpdated({ + stripeCli, + env, + event, + req: request, + }); + break; + case "invoice.created": const createdInvoice = event.data.object; await handleInvoiceCreated({ diff --git a/server/src/external/stripe/webhookHandlers/handleCheckoutCompleted/handleRemainingSets.ts b/server/src/external/stripe/webhookHandlers/handleCheckoutCompleted/handleRemainingSets.ts index 9e3f5c9ae..47532492a 100644 --- a/server/src/external/stripe/webhookHandlers/handleCheckoutCompleted/handleRemainingSets.ts +++ b/server/src/external/stripe/webhookHandlers/handleCheckoutCompleted/handleRemainingSets.ts @@ -101,7 +101,8 @@ export const handleRemainingSets = async ({ })) as Stripe.Subscription; subs.push(subscription); - invoiceIds.push(subscription.latest_invoice as string); + const latestInvoice = subscription.latest_invoice as Stripe.Invoice; + invoiceIds.push(latestInvoice.id); } return { diff --git a/server/src/external/stripe/webhookHandlers/handleInvoicePaid.ts b/server/src/external/stripe/webhookHandlers/handleInvoicePaid.ts index 52790bb8d..1210e9474 100644 --- a/server/src/external/stripe/webhookHandlers/handleInvoicePaid.ts +++ b/server/src/external/stripe/webhookHandlers/handleInvoicePaid.ts @@ -22,6 +22,7 @@ import { DrizzleCli } from "@/db/initDrizzle.js"; import { InvoiceService } from "@/internal/invoices/InvoiceService.js"; import { getInvoiceItems } from "@/internal/invoices/invoiceUtils.js"; import { handleInvoicePaidDiscount } from "./handleInvoicePaidDiscount.js"; +import { handleInvoiceCheckoutPaid } from "@/internal/customers/attach/attachFunctions/invoiceCheckoutPaid/handleInvoiceCheckoutPaid.js"; const handleOneOffInvoicePaid = async ({ db, @@ -92,12 +93,12 @@ const convertToChargeAutomatically = async ({ logger.info(`Converting to charge automatically`); // 1. Get payment intent const paymentIntent = await stripeCli.paymentIntents.retrieve( - invoice.payment_intent as string, + invoice.payment_intent as string ); // 2. Get payment method const paymentMethod = await stripeCli.paymentMethods.retrieve( - paymentIntent.payment_method as string, + paymentIntent.payment_method as string ); await stripeCli.paymentMethods.attach(paymentMethod.id, { @@ -113,7 +114,7 @@ const convertToChargeAutomatically = async ({ }); } catch (error) { logger.warn( - `Convert to charge automatically: error updating subscription ${sub.id}`, + `Convert to charge automatically: error updating subscription ${sub.id}` ); logger.warn(error); } @@ -153,6 +154,17 @@ export const handleInvoicePaid = async ({ stripeId: invoiceData.id, }); + if (invoice.metadata?.autumn_metadata_id) { + await handleInvoiceCheckoutPaid({ + req, + org, + env, + db, + stripeCli, + invoice, + }); + } + await handleInvoicePaidDiscount({ db, expandedInvoice: invoice, @@ -174,7 +186,7 @@ export const handleInvoicePaid = async ({ // TODO: Send alert if (invoice.livemode) { logger.warn( - `invoice.paid: customer product not found for invoice ${invoice.id}`, + `invoice.paid: customer product not found for invoice ${invoice.id}` ); } return; @@ -199,7 +211,7 @@ export const handleInvoicePaid = async ({ let invoiceItems = await getInvoiceItems({ stripeInvoice: invoice, prices: activeCusProducts.flatMap((p) => - p.customer_prices.map((cpr: FullCustomerPrice) => cpr.price), + p.customer_prices.map((cpr: FullCustomerPrice) => cpr.price) ), logger, }); diff --git a/server/src/external/stripe/webhookHandlers/handleInvoiceUpdated.ts b/server/src/external/stripe/webhookHandlers/handleInvoiceUpdated.ts new file mode 100644 index 000000000..24bd0a0c8 --- /dev/null +++ b/server/src/external/stripe/webhookHandlers/handleInvoiceUpdated.ts @@ -0,0 +1,39 @@ +import { AppEnv, InvoiceStatus } from "@autumn/shared"; +import Stripe from "stripe"; +import { getFullStripeInvoice } from "../stripeInvoiceUtils.js"; +import { InvoiceService } from "@/internal/invoices/InvoiceService.js"; + +export const handleInvoiceUpdated = async ({ + env, + event, + stripeCli, + req, +}: { + env: AppEnv; + event: Stripe.Event; + stripeCli: Stripe; + req: any; +}) => { + const invoiceObject = event.data.object as Stripe.Invoice; + const invoice = await getFullStripeInvoice({ + stripeCli, + stripeId: invoiceObject.id, + }); + + const prevAttributes = event.data.previous_attributes as any; + const invoiceVoided = + prevAttributes?.status !== "void" && invoice.status === "void"; + + const { logger } = req; + + if (invoiceVoided) { + logger.info(`Invoice has been voided!`); + await InvoiceService.updateByStripeId({ + db: req.db, + stripeId: invoiceObject.id, + updates: { + status: InvoiceStatus.Void, + }, + }); + } +}; diff --git a/server/src/internal/api/events/usageRouter.ts b/server/src/internal/api/events/usageRouter.ts index 7af89e419..d5d046922 100644 --- a/server/src/internal/api/events/usageRouter.ts +++ b/server/src/internal/api/events/usageRouter.ts @@ -202,6 +202,12 @@ export const handleUsageEvent = async ({ entityId: entity_id, }; + // console.log("Customer:", customer); + // console.log( + // "Is paid continuous use:", + // isPaidContinuousUse({ feature, fullCus: customer }) + // ); + if (isPaidContinuousUse({ feature, fullCus: customer })) { console.log(`Running update usage task synchronously`); await runUpdateUsageTask({ diff --git a/server/src/internal/customers/add-product/handleCreateInvoiceCheckout.ts b/server/src/internal/customers/add-product/handleCreateInvoiceCheckout.ts new file mode 100644 index 000000000..f9eb4349a --- /dev/null +++ b/server/src/internal/customers/add-product/handleCreateInvoiceCheckout.ts @@ -0,0 +1,99 @@ +import RecaseError from "@/utils/errorUtils.js"; +import { + AttachParams, + AttachResultSchema, +} from "../cusProducts/AttachParams.js"; +import { createStripeCli } from "@/external/stripe/utils.js"; +import { createCheckoutMetadata } from "@/internal/metadata/metadataUtils.js"; +import { getStripeSubItems } from "@/external/stripe/stripeSubUtils/getStripeSubItems.js"; +import { ErrCode } from "@/errors/errCodes.js"; +import { getNextStartOfMonthUnix } from "@/internal/products/prices/billingIntervalUtils.js"; +import { isOneOff } from "@/internal/products/productUtils.js"; +import { attachParamsToProduct } from "../attach/attachUtils/convertAttachParams.js"; +import { handlePaidProduct } from "../attach/attachFunctions/addProductFlow/handlePaidProduct.js"; +import { + AttachBranch, + AttachConfig, + ProrationBehavior, + SuccessCode, +} from "@autumn/shared"; +import Stripe from "stripe"; +import { handleOneOffFunction } from "../attach/attachFunctions/addProductFlow/handleOneOffFunction.js"; + +export const handleCreateInvoiceCheckout = async ({ + req, + res, + attachParams, + config, +}: { + req: any; + res?: any; + attachParams: AttachParams; + config: AttachConfig; +}) => { + // if one off + const { stripeCli } = attachParams; + + let invoiceResult; + if (isOneOff(attachParams.prices)) { + invoiceResult = await handleOneOffFunction({ + req, + res, + attachParams, + config, + }); + } else { + invoiceResult = await handlePaidProduct({ + req, + res, + attachParams, + config, + }); + } + + const { invoices, anchorToUnix, subs }: any = invoiceResult; + + const metadataId = await createCheckoutMetadata({ + db: req.db, + attachParams: { + ...attachParams, + anchorToUnix, + subIds: subs.map((s: Stripe.Subscription) => s.id), + config, + } as any, + }); + + for (const invoice of invoices) { + await stripeCli.invoices.update(invoice.id, { + metadata: { + autumn_metadata_id: metadataId, + }, + }); + } + + // AttachResultSchema.parse({ + // checkout_url: checkout.url, + // code: SuccessCode.CheckoutCreated, + // message: `Successfully created checkout for customer ${ + // customer.id || customer.internal_id + // }, product(s) ${attachParams.products.map((p) => p.name).join(", ")}`, + // product_ids: attachParams.products.map((p) => p.id), + // customer_id: customer.id || customer.internal_id, + // }); + if (res) { + res.status(200).json( + AttachResultSchema.parse({ + checkout_url: invoices[0].hosted_invoice_url, + code: SuccessCode.CheckoutCreated, + message: `Successfully created invoice checkout for customer ${ + attachParams.customer.id || attachParams.customer.internal_id + }, product(s) ${attachParams.products.map((p) => p.name).join(", ")}`, + product_ids: attachParams.products.map((p) => p.id), + customer_id: + attachParams.customer.id || attachParams.customer.internal_id, + }) + ); + } + + return { invoices }; +}; diff --git a/server/src/internal/customers/attach/attachFunctions/addProductFlow/handleOneOffFunction.ts b/server/src/internal/customers/attach/attachFunctions/addProductFlow/handleOneOffFunction.ts index f2ba40aa4..9ef0eae74 100644 --- a/server/src/internal/customers/attach/attachFunctions/addProductFlow/handleOneOffFunction.ts +++ b/server/src/internal/customers/attach/attachFunctions/addProductFlow/handleOneOffFunction.ts @@ -106,7 +106,7 @@ export const handleOneOffFunction = async ({ // Create invoice logger.info("1. Creating invoice"); - const stripeInvoice = await stripeCli.invoices.create({ + let stripeInvoice = await stripeCli.invoices.create({ customer: customer.processor.id!, auto_advance: false, currency: org.default_currency!, @@ -117,6 +117,8 @@ export const handleOneOffFunction = async ({ }, ] : undefined, + collection_method: attachParams.invoiceOnly ? "send_invoice" : undefined, + days_until_due: attachParams.invoiceOnly ? 30 : undefined, }); logger.info("2. Creating invoice items"); @@ -128,6 +130,23 @@ export const handleOneOffFunction = async ({ } as any); } + if (config.invoiceCheckout) { + if (stripeInvoice.status === "draft") { + stripeInvoice = await stripeCli.invoices.finalizeInvoice( + stripeInvoice.id + ); + } + + await insertInvoiceFromAttach({ + db: req.db, + attachParams, + invoiceId: stripeInvoice.id, + logger, + }); + + return { invoices: [stripeInvoice], subs: [], anchorToUnix: undefined }; + } + // Create invoice items if (!invoiceOnly) { await stripeCli.invoices.finalizeInvoice(stripeInvoice.id); diff --git a/server/src/internal/customers/attach/attachFunctions/addProductFlow/handlePaidProduct.ts b/server/src/internal/customers/attach/attachFunctions/addProductFlow/handlePaidProduct.ts index ac5e55f7d..919759d83 100644 --- a/server/src/internal/customers/attach/attachFunctions/addProductFlow/handlePaidProduct.ts +++ b/server/src/internal/customers/attach/attachFunctions/addProductFlow/handlePaidProduct.ts @@ -1,3 +1,5 @@ +import RecaseError from "@/utils/errorUtils.js"; + import { getStripeSubs } from "@/external/stripe/stripeSubUtils.js"; import { createStripeSub } from "@/external/stripe/stripeSubUtils/createStripeSub.js"; import { getStripeSubItems } from "@/external/stripe/stripeSubUtils/getStripeSubItems.js"; @@ -14,8 +16,6 @@ import { } from "@/internal/invoices/invoiceUtils.js"; import { getNextStartOfMonthUnix } from "@/internal/products/prices/billingIntervalUtils.js"; import { attachToInsertParams } from "@/internal/products/productUtils.js"; -import RecaseError from "@/utils/errorUtils.js"; -import { formatUnixToDateTime } from "@/utils/genUtils.js"; import { ExtendedRequest } from "@/utils/models/Request.js"; import { APIVersion, @@ -122,7 +122,7 @@ export const handlePaidProduct = async ({ freeTrial, invoiceOnly, itemSet, - finalizeInvoice: attachParams.finalizeInvoice, + finalizeInvoice: config.invoiceCheckout, anchorToUnix: billingCycleAnchorUnix, reward: i == 0 ? reward : undefined, now: attachParams.now, @@ -148,9 +148,6 @@ export const handlePaidProduct = async ({ } } - // Add product and entitlements to customer - const batchInsert = []; - const anchorToUnix = subscriptions.length > 0 ? subscriptions[0].current_period_end * 1000 @@ -158,6 +155,32 @@ export const handlePaidProduct = async ({ ? mergeSubs[0].current_period_end * 1000 : undefined; + const batchInsertInvoice: any = []; + for (const sub of subscriptions) { + batchInsertInvoice.push( + insertInvoiceFromAttach({ + db: req.db, + // invoiceId: sub.latest_invoice as string, + stripeInvoice: sub.latest_invoice as Stripe.Invoice, + attachParams, + logger, + }) + ); + } + const invoices = await Promise.all(batchInsertInvoice); + + if (config.invoiceCheckout) { + return { + invoices: subscriptions.map((s) => s.latest_invoice as Stripe.Invoice), + subs: subscriptions, + anchorToUnix, + config, + }; + } + + // Add product and entitlements to customer + const batchInsert = []; + for (const product of products) { batchInsert.push( createFullCusProduct({ @@ -173,19 +196,6 @@ export const handlePaidProduct = async ({ } await Promise.all(batchInsert); - const batchInsertInvoice: any = []; - for (const sub of subscriptions) { - batchInsertInvoice.push( - insertInvoiceFromAttach({ - db: req.db, - invoiceId: sub.latest_invoice as string, - attachParams, - logger, - }) - ); - } - const invoices = await Promise.all(batchInsertInvoice); - if (res) { let apiVersion = attachParams.apiVersion || APIVersion.v1; const productNames = products.map((p) => p.name).join(", "); diff --git a/server/src/internal/customers/attach/attachFunctions/attachFuncUtils.ts b/server/src/internal/customers/attach/attachFunctions/attachFuncUtils.ts index fe974c146..5d55c32b9 100644 --- a/server/src/internal/customers/attach/attachFunctions/attachFuncUtils.ts +++ b/server/src/internal/customers/attach/attachFunctions/attachFuncUtils.ts @@ -8,10 +8,14 @@ export const addSubItemsToRemove = async ({ cusProduct, itemSet, }: { - sub: Stripe.Subscription; + sub?: Stripe.Subscription | null; cusProduct: FullCusProduct; itemSet: ItemSet; }) => { + if (!sub) { + return; + } + for (const item of sub.items.data) { let shouldRemove = subItemInCusProduct({ cusProduct, diff --git a/server/src/internal/customers/attach/attachFunctions/invoiceCheckoutPaid/handleInvoiceCheckoutPaid.ts b/server/src/internal/customers/attach/attachFunctions/invoiceCheckoutPaid/handleInvoiceCheckoutPaid.ts new file mode 100644 index 000000000..b693b4430 --- /dev/null +++ b/server/src/internal/customers/attach/attachFunctions/invoiceCheckoutPaid/handleInvoiceCheckoutPaid.ts @@ -0,0 +1,64 @@ +import { DrizzleCli } from "@/db/initDrizzle.js"; +import { createFullCusProduct } from "@/internal/customers/add-product/createFullCusProduct.js"; +import { AttachParams } from "@/internal/customers/cusProducts/AttachParams.js"; +import { MetadataService } from "@/internal/metadata/MetadataService.js"; +import { attachToInsertParams } from "@/internal/products/productUtils.js"; +import { ExtendedRequest } from "@/utils/models/Request.js"; +import { AppEnv, AttachScenario, Organization } from "@autumn/shared"; +import Stripe from "stripe"; + +export const handleInvoiceCheckoutPaid = async ({ + req, + org, + env, + db, + stripeCli, + invoice, +}: { + req: ExtendedRequest; + org: Organization; + env: AppEnv; + db: DrizzleCli; + stripeCli: Stripe; + invoice: Stripe.Invoice; +}) => { + const metadataId = invoice.metadata?.autumn_metadata_id!; + + const metadata = await MetadataService.get({ + db, + id: metadataId, + }); + + const { subIds, anchorToUnix, config, ...rest } = metadata?.data; + const attachParams = rest as AttachParams; + + if (!attachParams) { + return; + } + + const reqMatch = + attachParams.org.id === org.id && attachParams.customer.env === env; + + if (!reqMatch) return; + + const batchInsert = []; + for (const product of attachParams.products) { + batchInsert.push( + createFullCusProduct({ + db, + attachParams: attachToInsertParams(attachParams, product), + subscriptionIds: subIds, + anchorToUnix, + carryExistingUsages: config.carryUsage, + scenario: AttachScenario.New, + logger: req.logger, + }) + ); + } + + await Promise.all(batchInsert); + + req.logger.info( + `✅ invoice.paid, successfully inserted cus products: ${attachParams.products.map((p) => p.id).join(", ")}` + ); +}; diff --git a/server/src/internal/customers/attach/attachFunctions/upgradeDiffIntFlow/handleUpgradeDiffInt.ts b/server/src/internal/customers/attach/attachFunctions/upgradeDiffIntFlow/handleUpgradeDiffInt.ts index a6aecbb98..276839fa6 100644 --- a/server/src/internal/customers/attach/attachFunctions/upgradeDiffIntFlow/handleUpgradeDiffInt.ts +++ b/server/src/internal/customers/attach/attachFunctions/upgradeDiffIntFlow/handleUpgradeDiffInt.ts @@ -23,6 +23,7 @@ import { insertInvoiceFromAttach, } from "@/internal/invoices/invoiceUtils.js"; import { updateSubsDiffInt } from "./updateSubsDiffInt.js"; +import { attachParamsToCurCusProduct } from "../../attachUtils/convertAttachParams.js"; export const handleUpgradeDiffInterval = async ({ req, @@ -41,12 +42,12 @@ export const handleUpgradeDiffInterval = async ({ const product = products[0]; - let { curMainProduct: curCusProduct } = getExistingCusProducts({ - product, - cusProducts: cusProducts || [], - internalEntityId: attachParams.internalEntityId, - }); - + // let { curMainProduct: curCusProduct } = getExistingCusProducts({ + // product, + // cusProducts: cusProducts || [], + // internalEntityId: attachParams.internalEntityId, + // }); + let curCusProduct = attachParamsToCurCusProduct({ attachParams }); curCusProduct = curCusProduct!; const stripeSubs = await getStripeSubs({ diff --git a/server/src/internal/customers/attach/attachFunctions/upgradeDiffIntFlow/updateSubsDiffInt.ts b/server/src/internal/customers/attach/attachFunctions/upgradeDiffIntFlow/updateSubsDiffInt.ts index 0f3227d04..163f6db46 100644 --- a/server/src/internal/customers/attach/attachFunctions/upgradeDiffIntFlow/updateSubsDiffInt.ts +++ b/server/src/internal/customers/attach/attachFunctions/upgradeDiffIntFlow/updateSubsDiffInt.ts @@ -39,8 +39,8 @@ export const updateSubsDiffInt = async ({ carryExistingUsages: config.carryUsage, }); - const firstSub = stripeSubs[0]; - const firstItemSet = itemSets[0]; + const firstSub = stripeSubs?.[0]; + const firstItemSet = itemSets?.[0]; await addSubItemsToRemove({ sub: firstSub, @@ -127,7 +127,8 @@ export const updateSubsDiffInt = async ({ }); newSubs.push(newSub); - newInvoiceIds.push(newSub.latest_invoice as string); + const latestInvoice = newSub.latest_invoice as Stripe.Invoice; + newInvoiceIds.push(latestInvoice.id); } return { diff --git a/server/src/internal/customers/attach/attachFunctions/upgradeSameIntFlow/handleUpgradeSameInt.ts b/server/src/internal/customers/attach/attachFunctions/upgradeSameIntFlow/handleUpgradeSameInt.ts index 6a04c0187..7795a5582 100644 --- a/server/src/internal/customers/attach/attachFunctions/upgradeSameIntFlow/handleUpgradeSameInt.ts +++ b/server/src/internal/customers/attach/attachFunctions/upgradeSameIntFlow/handleUpgradeSameInt.ts @@ -2,7 +2,10 @@ import { AttachParams, AttachResultSchema, } from "@/internal/customers/cusProducts/AttachParams.js"; -import { attachParamToCusProducts } from "../../attachUtils/convertAttachParams.js"; +import { + attachParamsToCurCusProduct, + attachParamToCusProducts, +} from "../../attachUtils/convertAttachParams.js"; import { CusProductService } from "@/internal/customers/cusProducts/CusProductService.js"; import { createFullCusProduct } from "@/internal/customers/add-product/createFullCusProduct.js"; import { attachToInsertParams } from "@/internal/products/productUtils.js"; @@ -24,13 +27,11 @@ export const handleUpgradeSameInterval = async ({ attachParams: AttachParams; config: AttachConfig; }) => { - const { curMainProduct: curCusProduct } = attachParamToCusProducts({ - attachParams, - }); + const curCusProduct = attachParamsToCurCusProduct({ attachParams }); const stripeSubs = await getStripeSubs({ stripeCli: attachParams.stripeCli, - subIds: curCusProduct!.subscription_ids || [], + subIds: curCusProduct?.subscription_ids || [], expand: ["items.data.price.tiers"], }); diff --git a/server/src/internal/customers/attach/attachFunctions/upgradeSameIntFlow/updateSubsSameInt.ts b/server/src/internal/customers/attach/attachFunctions/upgradeSameIntFlow/updateSubsSameInt.ts index 44dd4c087..c0af66502 100644 --- a/server/src/internal/customers/attach/attachFunctions/upgradeSameIntFlow/updateSubsSameInt.ts +++ b/server/src/internal/customers/attach/attachFunctions/upgradeSameIntFlow/updateSubsSameInt.ts @@ -39,25 +39,11 @@ export const updateSubsByInt = async ({ attachParams.replaceables = replaceables; - // logger.info(`Cont use items`); - // logger.info( - // `New items: `, - // newItems.map( - // (item) => `${item.description} | Amount: ${item.amount || item.price}`, - // ), - // ); - // logger.info( - // "Replaceables: ", - // replaceables.map((r) => `${r.ent.feature_id}`), - // ); - const itemSets = await getStripeSubItems({ attachParams }); + const invoices: Stripe.Invoice[] = []; - // const replaceables: Replaceable[] = []; for (const sub of stripeSubs) { - // let interval = subToAutumnInterval(sub); - let subInterval = subToAutumnInterval(sub); let itemSet = itemSets.find((itemSet) => { return intervalsSame({ diff --git a/server/src/internal/customers/attach/attachRouter.ts b/server/src/internal/customers/attach/attachRouter.ts index 9a1046881..00282e821 100644 --- a/server/src/internal/customers/attach/attachRouter.ts +++ b/server/src/internal/customers/attach/attachRouter.ts @@ -1,6 +1,11 @@ import { Router } from "express"; import RecaseError from "@/utils/errorUtils.js"; -import { APIVersion, BillingType, FullCusProduct } from "@autumn/shared"; +import { + APIVersion, + AttachConfig, + BillingType, + FullCusProduct, +} from "@autumn/shared"; import { ErrCode } from "@/errors/errCodes.js"; import { getCusPaymentMethod } from "@/external/stripe/stripeCusUtils.js"; @@ -22,6 +27,7 @@ import { createStripePriceIFNotExist } from "@/external/stripe/createStripePrice import { notNullish, notNullOrUndefined, + nullish, nullOrUndefined, } from "@/utils/genUtils.js"; import { CusService } from "@/internal/customers/CusService.js"; @@ -35,14 +41,17 @@ import { handleAttachPreview } from "./handleAttachPreview/handleAttachPreview.j import { handleAttach } from "./handleAttach.js"; import { handleCheckout } from "./checkout/handleCheckout.js"; import { createStripeCusIfNotExists } from "@/external/stripe/stripeCusUtils.js"; +import { attachParamsToCurCusProduct } from "./attachUtils/convertAttachParams.js"; export const attachRouter: Router = Router(); export const handlePrepaidErrors = async ({ attachParams, + config, useCheckout = false, }: { attachParams: AttachParams; + config: AttachConfig; useCheckout?: boolean; }) => { const { prices, entitlements, optionsList } = attachParams; @@ -57,7 +66,8 @@ export const handlePrepaidErrors = async ({ let options = getEntOptions(optionsList, priceEnt); // 1. If not checkout, quantity should be defined - if (!useCheckout && nullOrUndefined(options?.quantity)) { + const regularCheckout = useCheckout && !config.invoiceCheckout; + if (!regularCheckout && nullOrUndefined(options?.quantity)) { throw new RecaseError({ message: `Pass in 'quantity' for feature ${priceEnt.feature_id} in options`, code: ErrCode.InvalidOptions, @@ -161,6 +171,7 @@ export const checkStripeConnections = async ({ } const batchProductUpdates = []; + if (createCus) { batchProductUpdates.push( createStripeCusIfNotExists({ @@ -172,6 +183,7 @@ export const checkStripeConnections = async ({ }) ); } + for (const product of products) { batchProductUpdates.push( checkStripeProductExists({ @@ -207,6 +219,9 @@ export const createStripePrices = async ({ const { prices, entitlements, products, org, stripeCli } = attachParams; const batchPriceUpdates = []; + + // const curCusProduct = attachParamsToCurCusProduct({ attachParams }); + for (const price of prices) { let product = getProductForPrice(price, products); diff --git a/server/src/internal/customers/attach/attachUtils/attachParams/checkToAttachParams.ts b/server/src/internal/customers/attach/attachUtils/attachParams/checkToAttachParams.ts index e352e61f9..ad19d234e 100644 --- a/server/src/internal/customers/attach/attachUtils/attachParams/checkToAttachParams.ts +++ b/server/src/internal/customers/attach/attachUtils/attachParams/checkToAttachParams.ts @@ -77,13 +77,6 @@ export const checkToAttachParams = async ({ // Others apiVersion, - // successUrl: attachBody.success_url, - // invoiceOnly: attachBody.invoice_only, - // billingAnchor: attachBody.billing_cycle_anchor, - // metadata: attachBody.metadata, - // disableFreeTrial: attachBody.free_trial === false || false, - // checkoutSessionParams: attachBody.checkout_session_params, - // isCustom: attachBody.is_custom, }; return attachParams; diff --git a/server/src/internal/customers/attach/attachUtils/attachParams/getAttachParams.ts b/server/src/internal/customers/attach/attachUtils/attachParams/getAttachParams.ts index 55e754e03..9870f7c63 100644 --- a/server/src/internal/customers/attach/attachUtils/attachParams/getAttachParams.ts +++ b/server/src/internal/customers/attach/attachUtils/attachParams/getAttachParams.ts @@ -66,8 +66,9 @@ export const getAttachParams = async ({ // Others apiVersion, successUrl: attachBody.success_url, - invoiceOnly: attachBody.invoice_only || attachBody.invoice, - finalizeInvoice: attachBody.invoice, + invoiceOnly: attachBody.invoice, + // || attachBody.invoice_only + billingAnchor: attachBody.billing_cycle_anchor, metadata: attachBody.metadata, disableFreeTrial: attachBody.free_trial === false || false, diff --git a/server/src/internal/customers/attach/attachUtils/convertAttachParams.ts b/server/src/internal/customers/attach/attachUtils/convertAttachParams.ts index 2a2bd5c04..9488f5b37 100644 --- a/server/src/internal/customers/attach/attachUtils/convertAttachParams.ts +++ b/server/src/internal/customers/attach/attachUtils/convertAttachParams.ts @@ -10,7 +10,7 @@ export const attachParamsToCurCusProduct = ({ const { curMainProduct, curSameProduct, curScheduledProduct } = attachParamToCusProducts({ attachParams }); - return curMainProduct || curSameProduct; + return curSameProduct || curMainProduct; }; export const attachParamToCusProducts = ({ diff --git a/server/src/internal/customers/attach/attachUtils/getAttachBranch.ts b/server/src/internal/customers/attach/attachUtils/getAttachBranch.ts index 526745120..10fc4c8a0 100644 --- a/server/src/internal/customers/attach/attachUtils/getAttachBranch.ts +++ b/server/src/internal/customers/attach/attachUtils/getAttachBranch.ts @@ -135,9 +135,6 @@ const checkSameCustom = async ({ features: attachParams.features, }); - // console.log("Attach params free trial:", attachParams.freeTrial); - // console.log("Cur same product free trial:", curSameProduct.free_trial); - if (itemsSame && freeTrialsSame) { throw new RecaseError({ message: `Items specified for ${product.name} are the same as the existing product, can't attach again`, @@ -145,6 +142,11 @@ const checkSameCustom = async ({ }); } + // const curPrices = cusProductToPrices({ cusProduct: curSameProduct }); + // if (isFreeProduct(curPrices) && !isFreeProduct(attachParams.prices)) { + // return AttachBranch.MainIsFree; + // } + if (onlyEntsChanged) { return AttachBranch.SameCustomEnts; } diff --git a/server/src/internal/customers/attach/attachUtils/getAttachConfig.ts b/server/src/internal/customers/attach/attachUtils/getAttachConfig.ts index 0f6929baf..a4d711835 100644 --- a/server/src/internal/customers/attach/attachUtils/getAttachConfig.ts +++ b/server/src/internal/customers/attach/attachUtils/getAttachConfig.ts @@ -23,7 +23,7 @@ export const intervalsAreSame = ({ attachParams, }); - let curCusProduct = curMainProduct || curSameProduct; + let curCusProduct = curSameProduct || curMainProduct; if (!curCusProduct) { return false; @@ -147,8 +147,17 @@ export const getAttachConfig = async ({ branch == AttachBranch.MainIsTrial || org.config.merge_billing_cycles === false; + const invoiceAndEnable = + attachParams.invoiceOnly && attachBody.enable_product_immediately; + + const invoiceCheckout = + attachParams.invoiceOnly === true && !attachBody.enable_product_immediately; + const checkoutFlow = - isPublic || forceCheckout || (noPaymentMethod && !invoiceOnly); + isPublic || + forceCheckout || + invoiceCheckout || + (noPaymentMethod && !invoiceAndEnable); const onlyCheckout = !isFree && checkoutFlow && !freeTrialWithoutCardRequired; @@ -159,6 +168,7 @@ export const getAttachConfig = async ({ proration, disableTrial, invoiceOnly: flags.invoiceOnly, + invoiceCheckout, disableMerge, sameIntervals, carryTrial, @@ -178,6 +188,7 @@ export const getDefaultAttachConfig = () => { disableMerge: false, sameIntervals: false, carryTrial: false, + invoiceCheckout: false, }; return config; diff --git a/server/src/internal/customers/attach/attachUtils/getAttachFunction.ts b/server/src/internal/customers/attach/attachUtils/getAttachFunction.ts index e15a3d410..b516c5ea7 100644 --- a/server/src/internal/customers/attach/attachUtils/getAttachFunction.ts +++ b/server/src/internal/customers/attach/attachUtils/getAttachFunction.ts @@ -25,6 +25,7 @@ import { deleteCurrentScheduledProduct } from "./deleteCurrentScheduledProduct.j import { handleOneOffFunction } from "../attachFunctions/addProductFlow/handleOneOffFunction.js"; import { handleUpgradeSameInterval } from "../attachFunctions/upgradeSameIntFlow/handleUpgradeSameInt.js"; import { CusProductService } from "../../cusProducts/CusProductService.js"; +import { handleCreateInvoiceCheckout } from "../../add-product/handleCreateInvoiceCheckout.js"; /* 1. If from new version, free trial should just carry over @@ -217,6 +218,14 @@ export const runAttachFunction = async ({ } if (attachFunction == AttachFunction.CreateCheckout) { + if (config.invoiceCheckout) { + return await handleCreateInvoiceCheckout({ + req, + res, + attachParams, + config, + }); + } return await handleCreateCheckout({ req, res, diff --git a/server/src/internal/customers/attach/attachUtils/handleAttachErrors.ts b/server/src/internal/customers/attach/attachUtils/handleAttachErrors.ts index 396dabac5..675075336 100644 --- a/server/src/internal/customers/attach/attachUtils/handleAttachErrors.ts +++ b/server/src/internal/customers/attach/attachUtils/handleAttachErrors.ts @@ -2,9 +2,15 @@ import RecaseError from "@/utils/errorUtils.js"; import { ErrCode } from "@/errors/errCodes.js"; import { StatusCodes } from "http-status-codes"; import { AttachParams } from "../../cusProducts/AttachParams.js"; -import { AttachBranch, AttachErrCode, UsagePriceConfig } from "@autumn/shared"; +import { + AttachBranch, + AttachConfig, + AttachErrCode, + UsagePriceConfig, +} from "@autumn/shared"; import { AttachBody } from "@autumn/shared"; -import { AttachConfig, AttachFlags } from "../models/AttachFlags.js"; +import { AttachFlags } from "../models/AttachFlags.js"; + import { getEntOptions, priceIsOneOffAndTiered, @@ -25,8 +31,10 @@ import { Decimal } from "decimal.js"; const handleNonCheckoutErrors = ({ flags, action, + config, }: { flags: AttachFlags; + config: AttachConfig; action: string; }) => { const { isPublic, forceCheckout, noPaymentMethod } = flags; @@ -47,14 +55,22 @@ const handleNonCheckoutErrors = ({ message: `Not allowed to ${action} because customer has no payment method on file`, code: ErrCode.InvalidRequest, }); + } else if (config.invoiceCheckout) { + throw new RecaseError({ + message: `Not allowed to ${action} when using 'invoice': true`, + code: ErrCode.InvalidRequest, + statusCode: StatusCodes.BAD_REQUEST, + }); } }; const handlePrepaidErrors = async ({ attachParams, + config, useCheckout = false, }: { attachParams: AttachParams; + config: AttachConfig; useCheckout?: boolean; }) => { const { prices, entitlements, optionsList } = attachParams; @@ -69,7 +85,10 @@ const handlePrepaidErrors = async ({ let options = getEntOptions(optionsList, priceEnt); // 1. If not checkout, quantity should be defined - if (!useCheckout && nullOrUndefined(options?.quantity)) { + + const regularCheckout = useCheckout && !config.invoiceCheckout; + + if (!regularCheckout && nullOrUndefined(options?.quantity)) { throw new RecaseError({ message: `Pass in 'quantity' for feature ${priceEnt.feature_id} in options`, code: ErrCode.InvalidOptions, @@ -197,6 +216,8 @@ export const handleAttachErrors = async ({ }) => { const { onlyCheckout } = config; + // Invoice no payment enabled: onlyCheckout + if (onlyCheckout || flags.isPublic) { let upgradeDowngradeFlows = [ AttachBranch.Upgrade, @@ -206,6 +227,7 @@ export const handleAttachErrors = async ({ if (upgradeDowngradeFlows.includes(branch)) { handleNonCheckoutErrors({ flags, + config, action: "perform upgrade or downgrade", }); } @@ -218,6 +240,7 @@ export const handleAttachErrors = async ({ handleNonCheckoutErrors({ flags, action: "update current product", + config, }); } } @@ -236,6 +259,7 @@ export const handleAttachErrors = async ({ await handlePrepaidErrors({ attachParams, + config, useCheckout: onlyCheckout, }); diff --git a/server/src/internal/customers/attach/checkout/handleCheckout.ts b/server/src/internal/customers/attach/checkout/handleCheckout.ts index f92bdecb5..5cd995d29 100644 --- a/server/src/internal/customers/attach/checkout/handleCheckout.ts +++ b/server/src/internal/customers/attach/checkout/handleCheckout.ts @@ -14,7 +14,10 @@ import { getAttachBranch } from "../attachUtils/getAttachBranch.js"; import { getAttachConfig } from "../attachUtils/getAttachConfig.js"; import { getAttachFunction } from "../attachUtils/getAttachFunction.js"; import { handleCreateCheckout } from "../../add-product/handleCreateCheckout.js"; -import { checkStripeConnections } from "../attachRouter.js"; +import { + checkStripeConnections, + handlePrepaidErrors, +} from "../attachRouter.js"; import { attachParamsToPreview } from "../handleAttachPreview/attachParamsToPreview.js"; import { previewToCheckoutRes } from "./previewToCheckoutRes.js"; import { getProductResponse } from "@/internal/products/productUtils/productResponseUtils/getProductResponse.js"; @@ -24,6 +27,7 @@ import { isPrepaidPrice } from "@/internal/products/prices/priceUtils/usagePrice import { priceToFeature } from "@/internal/products/prices/priceUtils/convertPrice.js"; import { getPriceOptions } from "@/internal/products/prices/priceUtils.js"; import { getHasProrations } from "./getHasProrations.js"; +import { handleCreateInvoiceCheckout } from "../../add-product/handleCreateInvoiceCheckout.js"; const getAttachVars = async ({ req, @@ -108,17 +112,13 @@ export const handleCheckout = (req: any, res: any) => const { logger, features } = req; const attachBody = AttachBodySchema.parse(req.body); - const { attachParams, branch, func } = await getAttachVars({ + const { attachParams, branch, func, config } = await getAttachVars({ req, attachBody, }); - await getCheckoutOptions({ - req, - attachParams, - }); - let checkoutUrl = null; + if (func == AttachFunction.CreateCheckout) { await checkStripeConnections({ req, @@ -127,33 +127,37 @@ export const handleCheckout = (req: any, res: any) => useCheckout: true, }); - const checkout = await handleCreateCheckout({ - req, - res, - attachParams, - returnCheckout: true, - }); + if (config.invoiceCheckout) { + await handlePrepaidErrors({ + attachParams, + config, + useCheckout: config.onlyCheckout, + }); - checkoutUrl = checkout?.url; + const result = await handleCreateInvoiceCheckout({ + req, + attachParams, + config, + }); - // const customer = attachParams.customer; - // res.status(200).json( - // CheckoutResponseSchema.parse({ - // url: checkout?.url, - // customer_id: customer.id || customer.internal_id, - // scenario: AttachScenario.New, - // lines: [], - // product: await getProductResponse({ - // product: attachParams.products[0], - // features: features, - // withDisplay: false, - // options: attachParams.optionsList, - // }), - // }) - // ); - // return; + checkoutUrl = result?.invoices?.[0]?.hosted_invoice_url; + } else { + const checkout = await handleCreateCheckout({ + req, + res, + attachParams, + returnCheckout: true, + }); + + checkoutUrl = checkout?.url; + } } + await getCheckoutOptions({ + req, + attachParams, + }); + const preview = await attachParamsToPreview({ req, attachParams, diff --git a/server/src/internal/customers/attach/handleAttachPreview/getNewProductPreview.ts b/server/src/internal/customers/attach/handleAttachPreview/getNewProductPreview.ts index 42dc67ea7..ac9fcbf93 100644 --- a/server/src/internal/customers/attach/handleAttachPreview/getNewProductPreview.ts +++ b/server/src/internal/customers/attach/handleAttachPreview/getNewProductPreview.ts @@ -64,7 +64,10 @@ export const getNewProductPreview = async ({ let dueNextCycle = null; - if (freeTrial || notNullish(anchorToUnix)) { + if ( + (freeTrial || notNullish(anchorToUnix)) && + branch != AttachBranch.OneOff + ) { let nextCycleItems = await getItemsForNewProduct({ newProduct, attachParams, diff --git a/server/src/internal/customers/attach/handleAttachPreview/handleAttachPreview.ts b/server/src/internal/customers/attach/handleAttachPreview/handleAttachPreview.ts index 01285787b..3fa87a05b 100644 --- a/server/src/internal/customers/attach/handleAttachPreview/handleAttachPreview.ts +++ b/server/src/internal/customers/attach/handleAttachPreview/handleAttachPreview.ts @@ -30,6 +30,9 @@ export const handleAttachPreview = (req: any, res: any) => logger, }); + console.log("Branch:", attachPreview.branch); + console.log("Func:", attachPreview.func); + res.status(200).json(attachPreview); return; diff --git a/server/src/internal/customers/cusCache/getCusWithCache.ts b/server/src/internal/customers/cusCache/getCusWithCache.ts index 229a56156..54f442a62 100644 --- a/server/src/internal/customers/cusCache/getCusWithCache.ts +++ b/server/src/internal/customers/cusCache/getCusWithCache.ts @@ -58,9 +58,7 @@ export const getCusWithCache = async ({ if (!skipCache && !skipGet) { try { - const start = Date.now(); const cached = await upstash!.get(cacheKey); - const end = Date.now(); if (cached) { return cached as FullCustomer; } else { @@ -88,8 +86,9 @@ export const getCusWithCache = async ({ if (!skipCache && notNullish(customer)) { try { - await upstash!.set(cacheKey, customer); - await upstash!.expire(cacheKey, 300); // Expire after 5 minutes... + await upstash!.set(cacheKey, customer, { + ex: 300, + }); } catch (error) { logger.error(`Failed to set cache: ${cacheKey}`, { error }); } diff --git a/server/src/internal/customers/cusProducts/cusProductUtils/convertCusProduct.ts b/server/src/internal/customers/cusProducts/cusProductUtils/convertCusProduct.ts index 8117bc74f..beb7d6ac1 100644 --- a/server/src/internal/customers/cusProducts/cusProductUtils/convertCusProduct.ts +++ b/server/src/internal/customers/cusProducts/cusProductUtils/convertCusProduct.ts @@ -16,10 +16,11 @@ import { import Stripe from "stripe"; import { DrizzleCli } from "@/db/initDrizzle.js"; import { getBillingType } from "@/internal/products/prices/priceUtils.js"; +import { ACTIVE_STATUSES } from "../CusProductService.js"; export const cusProductsToCusPrices = ({ cusProducts, - inStatuses = [CusProductStatus.Active], + inStatuses, billingType, }: { cusProducts: FullCusProduct[]; @@ -29,7 +30,7 @@ export const cusProductsToCusPrices = ({ const cusPrices: FullCustomerPrice[] = []; for (const cusProduct of cusProducts) { - if (!inStatuses.includes(cusProduct.status)) { + if (inStatuses && !inStatuses.includes(cusProduct.status)) { continue; } diff --git a/server/src/internal/customers/cusUtils/cusFeatureResponseUtils/getCusFeaturesResponse.ts b/server/src/internal/customers/cusUtils/cusFeatureResponseUtils/getCusFeaturesResponse.ts index 02003af13..c39b6a363 100644 --- a/server/src/internal/customers/cusUtils/cusFeatureResponseUtils/getCusFeaturesResponse.ts +++ b/server/src/internal/customers/cusUtils/cusFeatureResponseUtils/getCusFeaturesResponse.ts @@ -10,6 +10,7 @@ import { cusProductsToCusPrices, } from "../../cusProducts/cusProductUtils/convertCusProduct.js"; import { getCusBalances } from "./getCusBalances.js"; +import { ACTIVE_STATUSES } from "../../cusProducts/CusProductService.js"; export const getCusFeaturesResponse = async ({ cusProducts, @@ -26,7 +27,9 @@ export const getCusFeaturesResponse = async ({ const balances = await getCusBalances({ cusEntsWithCusProduct: cusEnts, - cusPrices: cusProductsToCusPrices({ cusProducts }), + cusPrices: cusProductsToCusPrices({ + cusProducts, + }), org, entity, apiVersion, diff --git a/server/src/internal/customers/cusUtils/getOrCreateCustomer.ts b/server/src/internal/customers/cusUtils/getOrCreateCustomer.ts index 97afd7e97..c22a9756f 100644 --- a/server/src/internal/customers/cusUtils/getOrCreateCustomer.ts +++ b/server/src/internal/customers/cusUtils/getOrCreateCustomer.ts @@ -96,6 +96,7 @@ export const getOrCreateCustomer = async ({ email: customerData?.email, fingerprint: customerData?.fingerprint, metadata: customerData?.metadata || {}, + stripe_id: customerData?.stripe_id, }, }); diff --git a/server/src/internal/customers/handlers/handleCreateCustomer.ts b/server/src/internal/customers/handlers/handleCreateCustomer.ts index c9231263f..dc02fd4b2 100644 --- a/server/src/internal/customers/handlers/handleCreateCustomer.ts +++ b/server/src/internal/customers/handlers/handleCreateCustomer.ts @@ -50,7 +50,7 @@ export const initStripeCusAndProducts = async ({ env, logger, product, - }), + }) ); } @@ -90,7 +90,7 @@ const handleIdIsNull = async ({ for (const existingCustomer of existingCustomers) { if (existingCustomer.id === null) { logger.info( - `Create customer by email: ${newCus.email} already exists, skipping...`, + `Create customer by email: ${newCus.email} already exists, skipping...` ); return existingCustomer; } @@ -134,7 +134,7 @@ export const handleCreateCustomerWithId = async ({ if (existingCustomer) { logger.info( - `Customer already exists, skipping creation: ${existingCustomer.id}`, + `Customer already exists, skipping creation: ${existingCustomer.id}` ); return existingCustomer; } @@ -150,7 +150,7 @@ export const handleCreateCustomerWithId = async ({ if (cusWithEmail.length === 1 && cusWithEmail[0].id === null) { logger.info( - `POST /customers, email ${newCus.email} and ID null found, updating ID to ${newCus.id} (org: ${org.slug})`, + `POST /customers, email ${newCus.email} and ID null found, updating ID to ${newCus.id} (org: ${org.slug})` ); let updatedCustomer = await CusService.update({ @@ -185,6 +185,7 @@ export const handleCreateCustomer = async ({ createDefaultProducts?: boolean; }) => { const newCus = CreateCustomerSchema.parse(cusData); + console.log("newCus", newCus); // 1. If no ID and email is not NULL let createdCustomer; diff --git a/server/src/internal/customers/handlers/handlePostCustomer.ts b/server/src/internal/customers/handlers/handlePostCustomer.ts index 70fe58e96..bfbe89c1c 100644 --- a/server/src/internal/customers/handlers/handlePostCustomer.ts +++ b/server/src/internal/customers/handlers/handlePostCustomer.ts @@ -11,6 +11,7 @@ export const handlePostCustomerRequest = async (req: any, res: any) => { const logger = req.logtail; try { const data = req.body; + const expand = parseCusExpand(req.query.expand); const { db, org, features } = req; diff --git a/server/src/internal/customers/handlers/handleUpdateCustomer.ts b/server/src/internal/customers/handlers/handleUpdateCustomer.ts index f8eff40a6..f74eb926a 100644 --- a/server/src/internal/customers/handlers/handleUpdateCustomer.ts +++ b/server/src/internal/customers/handlers/handleUpdateCustomer.ts @@ -4,7 +4,7 @@ import { OrgService } from "@/internal/orgs/OrgService.js"; import RecaseError from "@/utils/errorUtils.js"; import { notNullish } from "@/utils/genUtils.js"; import { routeHandler } from "@/utils/routerUtils.js"; -import { CreateCustomerSchema, ErrCode } from "@autumn/shared"; +import { CreateCustomerSchema, ErrCode, ProcessorType } from "@autumn/shared"; import { StatusCodes } from "http-status-codes"; import { getCustomerDetails } from "../cusUtils/getCustomerDetails.js"; import { parseCusExpand } from "../cusUtils/cusUtils.js"; @@ -69,6 +69,20 @@ export const handleUpdateCustomer = async (req: any, res: any) => delete newCusData.id; } + // Try to update stripe ID + let stripeId = originalCustomer.processor?.id; + let newStripeId = newCusData.stripe_id; + + if (notNullish(newStripeId) && stripeId !== newStripeId) { + const stripeCli = createStripeCli({ org, env: req.env }); + await stripeCli.customers.retrieve(newStripeId); + + stripeId = newCusData.stripe_id; + req.logger.info( + `Updating customer's Stripe ID from ${originalCustomer.processor?.id} to ${stripeId}` + ); + } + // 2. Check if customer email is being changed let oldMetadata = originalCustomer.metadata || {}; let newMetadata = newCusData.metadata || {}; @@ -90,15 +104,9 @@ export const handleUpdateCustomer = async (req: any, res: any) => : undefined, }; - if ( - Object.keys(stripeUpdate).length > 0 && - originalCustomer.processor?.id - ) { + if (Object.keys(stripeUpdate).length > 0 && stripeId) { const stripeCli = createStripeCli({ org, env: req.env }); - await stripeCli.customers.update( - originalCustomer.processor.id, - stripeUpdate as any - ); + await stripeCli.customers.update(stripeId, stripeUpdate as any); } await CusService.update({ @@ -106,6 +114,9 @@ export const handleUpdateCustomer = async (req: any, res: any) => internalCusId: originalCustomer.internal_id, update: { ...newCusData, + processor: newStripeId + ? { id: newStripeId, type: ProcessorType.Stripe } + : undefined, metadata: { ...oldMetadata, ...newMetadata, diff --git a/server/src/internal/features/featureUtils.ts b/server/src/internal/features/featureUtils.ts index b9d6aee1d..f64a5975f 100644 --- a/server/src/internal/features/featureUtils.ts +++ b/server/src/internal/features/featureUtils.ts @@ -23,6 +23,7 @@ import { cusProductToPrices, } from "../customers/cusProducts/cusProductUtils/convertCusProduct.js"; import { priceToFeature } from "../products/prices/priceUtils/convertPrice.js"; +import { ACTIVE_STATUSES } from "../customers/cusProducts/CusProductService.js"; export const validateFeatureId = (featureId: string) => { if (!featureId.match(/^[a-zA-Z0-9_-]+$/)) { @@ -227,7 +228,9 @@ export const isPaidContinuousUse = ({ let cusPrices = cusProductsToCusPrices({ cusProducts: fullCus.customer_products, + inStatuses: ACTIVE_STATUSES, }); + let hasPaid = cusPrices.some((cp) => { let config = cp.price.config as UsagePriceConfig; if (config.internal_feature_id == feature.internal_id) { diff --git a/server/src/internal/invoices/previewItemUtils/getItemsForCurProduct.ts b/server/src/internal/invoices/previewItemUtils/getItemsForCurProduct.ts index 565637e4e..3c0172396 100644 --- a/server/src/internal/invoices/previewItemUtils/getItemsForCurProduct.ts +++ b/server/src/internal/invoices/previewItemUtils/getItemsForCurProduct.ts @@ -53,7 +53,7 @@ export const getItemsForCurProduct = async ({ const curPrices = cusProductToPrices({ cusProduct: curCusProduct }); let items: PreviewLineItem[] = []; - let onTrial = isTrialing(curMainProduct!); + let onTrial = isTrialing(curCusProduct); for (const sub of stripeSubs) { for (const item of sub.items.data) { diff --git a/server/src/internal/metadata/metadataUtils.ts b/server/src/internal/metadata/metadataUtils.ts index 0ad4c3a1b..6d900624b 100644 --- a/server/src/internal/metadata/metadataUtils.ts +++ b/server/src/internal/metadata/metadataUtils.ts @@ -36,7 +36,7 @@ export const createCheckoutMetadata = async ({ export const getMetadataFromCheckoutSession = async ( checkoutSession: Stripe.Checkout.Session, - db: DrizzleCli, + db: DrizzleCli ) => { const metadataId = checkoutSession.metadata?.autumn_metadata_id; diff --git a/server/src/internal/migrations/migrationUtils/migrationToAttachParams.ts b/server/src/internal/migrations/migrationUtils/migrationToAttachParams.ts index fafa9b7c5..f03ffd724 100644 --- a/server/src/internal/migrations/migrationUtils/migrationToAttachParams.ts +++ b/server/src/internal/migrations/migrationUtils/migrationToAttachParams.ts @@ -60,13 +60,6 @@ export const migrationToAttachParams = async ({ // Others apiVersion, - // successUrl: attachBody.success_url, - // invoiceOnly: attachBody.invoice_only, - // billingAnchor: attachBody.billing_cycle_anchor, - // metadata: attachBody.metadata, - // disableFreeTrial: attachBody.free_trial === false || false, - // checkoutSessionParams: attachBody.checkout_session_params, - // isCustom: attachBody.is_custom, }; return attachParams; diff --git a/server/src/internal/platform/platformRouter.ts b/server/src/internal/platform/platformRouter.ts index 07812c3d7..8a7dd4857 100644 --- a/server/src/internal/platform/platformRouter.ts +++ b/server/src/internal/platform/platformRouter.ts @@ -19,6 +19,7 @@ import { z } from "zod"; import { createKey } from "../dev/api-keys/apiKeyUtils.js"; import { afterOrgCreated } from "@/utils/authUtils/afterOrgCreated.js"; import { Autumn } from "autumn-js"; +import { organizationSchema } from "better-auth/plugins"; const platformRouter = Router(); @@ -63,6 +64,14 @@ const platformAuthMiddleware = async ( platformRouter.use(platformAuthMiddleware); const ExchangeSchema = z.object({ + // organization_name: z.string().nullish(), + // organization_slug: z.string().nullish(), + organization: z + .object({ + name: z.string().nonempty(), + slug: z.string().nonempty(), + }) + .nullish(), email: z.string().regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/), stripe_test_key: z.string().nonempty().optional(), stripe_live_key: z.string().nonempty().optional(), @@ -121,9 +130,36 @@ platformRouter.post("/exchange", (req: any, res: any) => let org: Organization; - let membership = await db.query.member.findFirst({ - where: and(eq(member.userId, user.id!), eq(member.role, "owner")), - }); + // let membership = await db.query.member.findFirst({ + // with: { + // organization: true, + // }, + // where: and( + // eq(member.userId, user.id!), + // eq(member.role, "owner"), + // organization_slug + // ? eq(organizations.slug, organization_slug) + // : undefined, + // eq(organizations.created_by, req.org.id) + // ), + // }); + const orgSlug = organization?.slug + ? `${organization.slug}_${req.org.id}` + : undefined; + const data = await db + .select() + .from(member) + .innerJoin(organizations, eq(member.organizationId, organizations.id)) + .where( + and( + eq(member.userId, user.id!), + eq(member.role, "owner"), + orgSlug ? eq(organizations.slug, orgSlug) : undefined, + eq(organizations.created_by, req.org.id) + ) + ); + + let membership = data.length > 0 ? data[0] : null; if (!membership) { logger.info(`Connected to Stripe`); @@ -135,8 +171,11 @@ platformRouter.post("/exchange", (req: any, res: any) => .insert(organizations) .values({ id: orgId, - slug: `platform_org_${Math.floor(10000000 + Math.random() * 90000000)}`, - name: `Platform Org`, + slug: orgSlug + ? orgSlug + : `platform_org_${Math.floor(10000000 + Math.random() * 90000000)}`, + + name: organization?.name || `Platform Org (${req.org.id})`, logo: "", createdAt: new Date(), metadata: "", @@ -154,9 +193,10 @@ platformRouter.post("/exchange", (req: any, res: any) => await afterOrgCreated({ org }); } else { - org = (await db.query.organizations.findFirst({ - where: eq(organizations.id, membership.organizationId), - })) as Organization; + // org = (await db.query.organizations.findFirst({ + // where: eq(organizations.id, membership.organizationId), + // })) as Organization; + org = membership.organizations as Organization; } let sandboxKey, prodKey; diff --git a/server/src/internal/products/prices/priceUtils/constructPriceUtils.ts b/server/src/internal/products/prices/priceUtils/constructPriceUtils.ts index cd29ac334..398d91a23 100644 --- a/server/src/internal/products/prices/priceUtils/constructPriceUtils.ts +++ b/server/src/internal/products/prices/priceUtils/constructPriceUtils.ts @@ -1,8 +1,7 @@ import Stripe from "stripe"; import { constructPrice } from "../priceUtils.js"; import { FullProduct, PriceType } from "@autumn/shared"; -import { generateId } from "@/utils/genUtils.js"; -import { subItemToAutumnInterval } from "tests/utils/stripeUtils.js"; +import { subItemToAutumnInterval } from "@/external/stripe/utils.js"; export const subItemToFixedPrice = ({ subItem, diff --git a/server/src/internal/products/product-items/validateProductItems.ts b/server/src/internal/products/product-items/validateProductItems.ts index e84c376bc..0c59c990e 100644 --- a/server/src/internal/products/product-items/validateProductItems.ts +++ b/server/src/internal/products/product-items/validateProductItems.ts @@ -60,40 +60,9 @@ const validateProductItem = ({ }); } - // 3. If tiers are set, final tier must be infinite, and amount must be > 0 - if (notNullish(item.tiers)) { - for (let i = 0; i < item.tiers!.length; i++) { - let tier = item.tiers![i]; - if (tier.amount < 0) { - throw new RecaseError({ - message: `Tier amount must be >= 0`, - code: ErrCode.InvalidProductItem, - statusCode: StatusCodes.BAD_REQUEST, - }); - } - - if (i > 0 && tier.to <= item.tiers![i - 1].to) { - throw new RecaseError({ - message: `Tier ${i + 1} should have a greater 'to' than tier ${i}`, - code: ErrCode.InvalidProductItem, - statusCode: StatusCodes.BAD_REQUEST, - }); - } - - if (i == item.tiers!.length - 1 && tier.to != TierInfinite) { - throw new RecaseError({ - message: `Final tier must be infinite${ - item.feature_id ? ` (feature: ${item.feature_id})` : "" - }`, - code: ErrCode.InvalidProductItem, - statusCode: StatusCodes.BAD_REQUEST, - }); - } - } - } - // 4. One off prices / fixed prices can have at most 2 decimal places - if ((isFeaturePriceItem(item) && !item.interval) || isPriceItem(item)) { + // (isFeaturePriceItem(item) && !item.interval && isOneOff) || + if (isPriceItem(item)) { // One off price..., can't have more than 2 DP if (item.price && item.price.toString().split(".")[1]?.length > 2) { throw new RecaseError({ @@ -103,17 +72,17 @@ const validateProductItem = ({ }); } - if (item.tiers) { - item.tiers.forEach((tier) => { - if (tier.amount.toString().split(".")[1]?.length > 2) { - throw new RecaseError({ - message: `One off prices can have at most 2 decimal places`, - code: ErrCode.InvalidInputs, - statusCode: StatusCodes.BAD_REQUEST, - }); - } - }); - } + // if (item.tiers) { + // item.tiers.forEach((tier) => { + // if (tier.amount.toString().split(".")[1]?.length > 2) { + // throw new RecaseError({ + // message: `One off prices can have at most 2 decimal places`, + // code: ErrCode.InvalidInputs, + // statusCode: StatusCodes.BAD_REQUEST, + // }); + // } + // }); + // } } // 4. If it's a feature item, it should have included usage as number or inf @@ -169,6 +138,7 @@ const validateProductItem = ({ // } // } }; + export const validateProductItems = ({ newItems, features, @@ -189,6 +159,13 @@ export const validateProductItems = ({ features = allFeatures; + // const isOneOff = + // newItems.every((item) => { + // if (isFeatureItem(item)) return true; + // return nullish(item.interval); + // }) && + // newItems.some((item) => isFeaturePriceItem(item) || isPriceItem(item)); + // 1. Check values for (let index = 0; index < newItems.length; index++) { validateProductItem({ item: newItems[index], features }); @@ -251,10 +228,23 @@ export const validateProductItems = ({ continue; } - if ( - isFeatureItem(otherItem) || - (item.usage_model && item.usage_model == otherItem?.usage_model) - ) { + if (isFeatureItem(otherItem) && isFeatureItem(item)) { + throw new RecaseError({ + message: `You're trying to create two items for the same feature (${item.feature_id}) with the same interval. Please make them into one item.`, + code: ErrCode.InvalidInputs, + statusCode: StatusCodes.BAD_REQUEST, + }); + } + + if (isFeatureItem(otherItem)) { + throw new RecaseError({ + message: `You have a usage-based price for for this feature (${item.feature_id}). If you're looking to create an overage item (eg. 100 free, then $0.5 thereafter), you should add it to the existing item.`, + code: ErrCode.InvalidInputs, + statusCode: StatusCodes.BAD_REQUEST, + }); + } + + if (item.usage_model && item.usage_model == otherItem?.usage_model) { throw new RecaseError({ message: `You're trying to add the same feature (${item.feature_id}), with the same reset interval. You should either change the reset interval of one of the items, or make one of them a prepaid quantity`, code: ErrCode.InvalidInputs, diff --git a/server/src/internal/products/productUtils/productResponseUtils/getProductItemDisplay.ts b/server/src/internal/products/productUtils/productResponseUtils/getProductItemDisplay.ts index 8da066d96..91809d76c 100644 --- a/server/src/internal/products/productUtils/productResponseUtils/getProductItemDisplay.ts +++ b/server/src/internal/products/productUtils/productResponseUtils/getProductItemDisplay.ts @@ -47,6 +47,7 @@ export const formatTiers = ({ return formatAmount({ currency, amount: tiers[0].amount, + maxFractionDigits: 10, }); } @@ -56,9 +57,11 @@ export const formatTiers = ({ return `${formatAmount({ currency, amount: firstPrice, + maxFractionDigits: 10, })} - ${formatAmount({ currency, amount: lastPrice, + maxFractionDigits: 10, })}`; } }; diff --git a/server/src/trigger/updateBalanceTask.ts b/server/src/trigger/updateBalanceTask.ts index 375424648..eb0b3575a 100644 --- a/server/src/trigger/updateBalanceTask.ts +++ b/server/src/trigger/updateBalanceTask.ts @@ -696,6 +696,7 @@ export const runUpdateBalanceTask = async ({ entityId, }); + // console.time("refreshCusCache"); await refreshCusCache({ db, customerId, @@ -703,6 +704,7 @@ export const runUpdateBalanceTask = async ({ env, entityId, }); + // console.timeEnd("refreshCusCache"); if (!cusEnts || cusEnts.length === 0) { return; diff --git a/server/src/utils/constants.ts b/server/src/utils/constants.ts index 0de0853e7..493aebd25 100644 --- a/server/src/utils/constants.ts +++ b/server/src/utils/constants.ts @@ -10,7 +10,11 @@ export const getActiveCusProductStatuses = () => [ export const ADMIN_USER_IDs = process.env.ENV == "production" || process.env.NODE_ENV == "production" - ? ["user_2tMgAiPsQzX8JTHjZZh9m0VdvUv", "user_2sB3tBXsnVVLlTKliQIqvvM2xfB"] + ? [ + "user_2tMgAiPsQzX8JTHjZZh9m0VdvUv", // a + "user_2sB3tBXsnVVLlTKliQIqvvM2xfB", // j + "ZsDswIXyOGMP9y1V1At4dAZNaiggClSs", // t + ] : ["user_2rypooIKyMQx81vMS8FFGx24UHU"]; export const dashboardOrigins = [ diff --git a/server/src/utils/errorUtils.ts b/server/src/utils/errorUtils.ts index 1177f8877..26701ba9b 100644 --- a/server/src/utils/errorUtils.ts +++ b/server/src/utils/errorUtils.ts @@ -143,8 +143,8 @@ export const handleRequestError = ({ ); res.status(400).json({ - message: error.message, - code: ErrCode.InvalidInputs, + message: `(Stripe Error) ${error.message}`, + code: `stripe_error`, }); } else if (error instanceof ZodError) { logger.error( diff --git a/server/src/utils/importUtils/addProductFromSubs.ts b/server/src/utils/importUtils/addProductFromSubs.ts index fb38378f9..958726ab5 100644 --- a/server/src/utils/importUtils/addProductFromSubs.ts +++ b/server/src/utils/importUtils/addProductFromSubs.ts @@ -56,9 +56,9 @@ export const addProductFromSubs = async ({ if (mainCusProduct && !force) { let prices = mainCusProduct.customer_prices.map((cp) => cp.price); - let isFree = isFreeProduct(prices); + // let isFree = isFreeProduct(prices); - if (!isFree) { + if (mainCusProduct) { logger.info( `Customer ${ autumnCus.id || autumnCus.email @@ -71,10 +71,12 @@ export const addProductFromSubs = async ({ } // Handle if trialing - let trialEndsAt = stripeSubs[0].trial_end + let trialEndsAt = stripeSubs?.[0]?.trial_end ? stripeSubs[0].trial_end * 1000 : null; + // throw new Error("test"); + // 1. Insert custom prices... let customPrices = prices?.filter((p) => p.is_custom); if (customPrices && customPrices.length > 0) { @@ -107,17 +109,17 @@ export const addProductFromSubs = async ({ logger, trialEndsAt: trialEndsAt || undefined, subscriptionIds: stripeSubs.map((s) => s.id), - anchorToUnix: anchorToUnix || stripeSubs[0].current_period_end * 1000, + anchorToUnix: anchorToUnix || stripeSubs?.[0]?.current_period_end * 1000, - subscriptionStatus: stripeToAutumnSubStatus( - stripeSubs[0].status - ) as CusProductStatus, + subscriptionStatus: stripeSubs?.[0]?.status + ? (stripeToAutumnSubStatus(stripeSubs[0].status) as CusProductStatus) + : undefined, - canceledAt: stripeSubs[0].canceled_at + canceledAt: stripeSubs?.[0]?.canceled_at ? stripeSubs[0].canceled_at * 1000 : null, - createdAt: stripeSubs[0].created * 1000, + createdAt: stripeSubs?.[0]?.created ? stripeSubs[0].created * 1000 : null, sendWebhook: false, }); diff --git a/server/src/utils/importUtils/addUsagePricesToSub.ts b/server/src/utils/importUtils/addUsagePricesToSub.ts index eb4618c98..79329acee 100644 --- a/server/src/utils/importUtils/addUsagePricesToSub.ts +++ b/server/src/utils/importUtils/addUsagePricesToSub.ts @@ -5,6 +5,7 @@ import { FullProduct, UsagePriceConfig, FullCusProduct, + BillingInterval, } from "@autumn/shared"; import Stripe from "stripe"; import { ExtendedRequest } from "../models/Request.js"; @@ -26,11 +27,15 @@ export const addContUsePricesToSub = async ({ quantity: number; logger: any; }) => { - const usagePrices = filterByBillingType({ + let usagePrices = filterByBillingType({ prices: autumnProduct.prices, billingType: BillingType.InArrearProrated, }); + usagePrices = usagePrices.filter( + (p) => p.config.interval !== BillingInterval.OneOff + ); + logger.info(`Adding ${usagePrices.length} cont use prices to sub`); for (const usagePrice of usagePrices) { @@ -100,12 +105,12 @@ export const addUsagePricesToSub = async ({ logger.info(`Adding ${config.feature_id} to sub ${stripeSub.id}`); let stripePrice = await stripeCli.prices.retrieve( - price.config.stripe_price_id!, + price.config.stripe_price_id! ); if (stripePrice.recurring?.usage_type !== "metered") { logger.info( - `Skipping ${config.feature_id} because it's not a metered price`, + `Skipping ${config.feature_id} because it's not a metered price` ); continue; } diff --git a/server/src/utils/importUtils/parseCsv.ts b/server/src/utils/importUtils/parseCsv.ts deleted file mode 100644 index fd98c0578..000000000 --- a/server/src/utils/importUtils/parseCsv.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { FeatureOptions } from "@autumn/shared"; -import csvParser from "csv-parser"; -import fs from "fs"; - -export interface ImportCustomer { - id: string; - name: string; - email?: string; - stripe_id: string; - product_id: string; - base_price?: number; - options?: FeatureOptions[]; - // business_id;name;email;active_pass_count;Stripe id;Base price;free_trial_end -} -export const parseCsv = ({ - slug, - filename, -}: { - slug: string; - filename?: string; -}): Promise => { - const path = `scripts/customers/${slug}/${filename || "data.csv"}`; - const results: ImportCustomer[] = []; - - return new Promise((resolve, reject) => { - const stream = fs.createReadStream(path); - stream - .pipe(csvParser({ separator: ";" })) - .on("data", (data) => - results.push({ - id: data.business_id, - name: data.name, - email: data.email, - stripe_id: data["Stripe id"], - // base_price: data["Base price"], - product_id: "standard_subscription", - base_price: data["Base price"], - options: [ - { - feature_id: "active_passes", - quantity: data["active_pass_count"], - }, - ], - }), - ) - .on("end", () => resolve(results)) - .on("error", (error) => reject(error)); - }); -}; diff --git a/server/src/utils/scriptUtils/clearOrg.ts b/server/src/utils/scriptUtils/clearOrg.ts index 59e0ccc10..999d6c360 100644 --- a/server/src/utils/scriptUtils/clearOrg.ts +++ b/server/src/utils/scriptUtils/clearOrg.ts @@ -8,7 +8,7 @@ import { } from "@autumn/shared"; import { and, eq, inArray } from "drizzle-orm"; -const clearCustomersInBatches = async ({ +export const clearCustomersInBatches = async ({ db, org, batchSize = 450, @@ -38,6 +38,8 @@ const clearCustomersInBatches = async ({ .map((c) => c.internalId) .filter((id) => id !== null); + console.log("Deleting customers:", customerIds); + await db .delete(customers) .where(inArray(customers.internal_id, customerIds)); diff --git a/server/src/utils/scriptUtils/genScriptUtils.ts b/server/src/utils/scriptUtils/genScriptUtils.ts index 588c80033..cd758f4d6 100644 --- a/server/src/utils/scriptUtils/genScriptUtils.ts +++ b/server/src/utils/scriptUtils/genScriptUtils.ts @@ -1,13 +1,19 @@ import csv from "csv-parser"; import fs from "fs"; -export const parseCsv = (path: string) => { +export const parseCsv = ({ + path, + delimiter = ",", +}: { + path: string; + delimiter?: string; +}) => { return new Promise((resolve, reject) => { const stream = fs.createReadStream(path); const results: any[] = []; let headers: string[] = []; stream - .pipe(csv({ separator: "," })) + .pipe(csv({ separator: delimiter })) .on("data", (data) => { results.push(data); // if (headers.length === 0) { diff --git a/server/tests/attach/addOn/addOn1.ts b/server/tests/attach/addOn/addOn1.ts new file mode 100644 index 000000000..426c84b4f --- /dev/null +++ b/server/tests/attach/addOn/addOn1.ts @@ -0,0 +1,158 @@ +import { AutumnInt } from "@/external/autumn/autumnCli.js"; +import { initCustomer } from "@/utils/scriptUtils/initCustomer.js"; +import { APIVersion, AppEnv, Organization } from "@autumn/shared"; +import chalk from "chalk"; +import Stripe from "stripe"; +import { DrizzleCli } from "@/db/initDrizzle.js"; +import { setupBefore } from "tests/before.js"; +import { createProducts } from "tests/utils/productUtils.js"; +import { addPrefixToProducts, replaceItems } from "../utils.js"; +import { + constructProduct, + constructRawProduct, +} from "@/utils/scriptUtils/createTestProducts.js"; +import { + constructArrearProratedItem, + constructFeatureItem, +} from "@/utils/scriptUtils/constructItem.js"; +import { TestFeature } from "tests/setup/v2Features.js"; +import { attachAndExpectCorrect } from "tests/utils/expectUtils/expectAttach.js"; +import { expect } from "chai"; +import { expectProductAttached } from "tests/utils/expectUtils/expectProductAttached.js"; + +export let pro = constructProduct({ + items: [ + constructFeatureItem({ + featureId: TestFeature.Messages, + includedUsage: 100, + }), + ], + type: "pro", +}); + +export let addOn = constructRawProduct({ + id: "add_on_1", + items: [ + constructFeatureItem({ + featureId: TestFeature.Messages, + includedUsage: 200, + }), + ], + isAddOn: true, +}); + +const testCase = "addOn1"; + +describe(`${chalk.yellowBright(`${testCase}: Testing free add on, and updating free add on`)}`, () => { + let customerId = testCase; + let autumn: AutumnInt = new AutumnInt({ version: APIVersion.v1_2 }); + let testClockId: string; + let db: DrizzleCli, org: Organization, env: AppEnv; + let stripeCli: Stripe; + + let curUnix = new Date().getTime(); + + before(async function () { + await setupBefore(this); + const { autumnJs } = this; + db = this.db; + org = this.org; + env = this.env; + + stripeCli = this.stripeCli; + + addPrefixToProducts({ + products: [pro, addOn], + prefix: testCase, + }); + + await createProducts({ + autumn, + products: [pro, addOn], + customerId, + db, + orgId: org.id, + env, + }); + + const { testClockId: testClockId1 } = await initCustomer({ + autumn: autumnJs, + customerId, + db, + org, + env, + attachPm: "success", + }); + + testClockId = testClockId1!; + }); + + it("should should attach pro product, then add on product", async function () { + await attachAndExpectCorrect({ + autumn, + db, + org, + env, + stripeCli, + customerId, + product: pro, + }); + }); + + it("should should attach add on product", async function () { + const preview = await autumn.attachPreview({ + customer_id: customerId, + product_id: addOn.id, + }); + + await autumn.attach({ + customer_id: customerId, + product_id: addOn.id, + }); + + const customer = await autumn.customers.get(customerId); + + expect(customer.products.length).to.equal(3); + expectProductAttached({ + customer, + product: addOn, + }); + expectProductAttached({ + customer, + product: pro, + }); + }); + + const customItems = replaceItems({ + items: addOn.items, + featureId: TestFeature.Messages, + newItem: constructFeatureItem({ + featureId: TestFeature.Messages, + includedUsage: 400, + }), + }); + + it("should update add on product", async function () { + const preview = await autumn.attachPreview({ + customer_id: customerId, + product_id: addOn.id, + is_custom: true, + items: customItems, + }); + + await autumn.attach({ + customer_id: customerId, + product_id: addOn.id, + is_custom: true, + items: customItems, + }); + + const customer = await autumn.customers.get(customerId); + + expect(customer.products.length).to.equal(3); + expectProductAttached({ + customer, + product: addOn, + }); + }); +}); diff --git a/server/tests/attach/checkout/checkout5.ts b/server/tests/attach/checkout/checkout5.ts new file mode 100644 index 000000000..9dfbb7b21 --- /dev/null +++ b/server/tests/attach/checkout/checkout5.ts @@ -0,0 +1,118 @@ +import { AutumnInt } from "@/external/autumn/autumnCli.js"; +import { initCustomer } from "@/utils/scriptUtils/initCustomer.js"; +import { APIVersion, AppEnv, Organization } from "@autumn/shared"; +import chalk from "chalk"; +import Stripe from "stripe"; +import { DrizzleCli } from "@/db/initDrizzle.js"; +import { setupBefore } from "tests/before.js"; +import { createProducts, createReward } from "tests/utils/productUtils.js"; +import { addPrefixToProducts } from "../utils.js"; +import { + constructCoupon, + constructProduct, +} from "@/utils/scriptUtils/createTestProducts.js"; +import { constructFeatureItem } from "@/utils/scriptUtils/constructItem.js"; +import { TestFeature } from "tests/setup/v2Features.js"; +import { completeCheckoutForm } from "tests/utils/stripeUtils.js"; +import { timeout } from "@/utils/genUtils.js"; +import { expectProductAttached } from "tests/utils/expectUtils/expectProductAttached.js"; +import { expect } from "chai"; +import { getBasePrice } from "tests/utils/testProductUtils/testProductUtils.js"; +import { completeInvoiceCheckout } from "tests/utils/stripeUtils/completeInvoiceCheckout.js"; +import { expectFeaturesCorrect } from "tests/utils/expectUtils/expectFeaturesCorrect.js"; + +export let pro = constructProduct({ + items: [ + constructFeatureItem({ + featureId: TestFeature.Messages, + includedUsage: 100, + }), + ], + type: "pro", +}); + +const testCase = "checkout5"; +describe(`${chalk.yellowBright(`${testCase}: Testing invoice checkout, no product till paid`)}`, () => { + let customerId = testCase; + let autumn: AutumnInt = new AutumnInt({ version: APIVersion.v1_2 }); + let testClockId: string; + let db: DrizzleCli, org: Organization, env: AppEnv; + let stripeCli: Stripe; + let curUnix = new Date().getTime(); + + before(async function () { + await setupBefore(this); + const { autumnJs } = this; + db = this.db; + org = this.org; + env = this.env; + + stripeCli = this.stripeCli; + + addPrefixToProducts({ + products: [pro], + prefix: testCase, + }); + + await createProducts({ + autumn, + products: [pro], + customerId, + db, + orgId: org.id, + env, + }); + + const { testClockId: testClockId1 } = await initCustomer({ + autumn: autumnJs, + customerId, + db, + org, + env, + // attachPm: "success", + }); + + testClockId = testClockId1!; + }); + + it("should attach pro product", async function () { + const res = await autumn.attach({ + customer_id: customerId, + product_id: pro.id, + invoice: true, + }); + + const customer = await autumn.customers.get(customerId); + + const invoice = customer.invoices?.[0]; + + expect(invoice).to.exist; + expect(invoice.total).to.equal(getBasePrice({ product: pro })); + expect(invoice.status).to.equal("open"); + + const product = customer.products.find((p) => p.id === pro.id); + expect(product).to.not.exist; + + await completeInvoiceCheckout({ + url: res.checkout_url, + }); + + const customer2 = await autumn.customers.get(customerId); + + const invoice2 = customer2.invoices?.[0]; + + expect(customer2.invoices.length).to.equal(1); + expect(invoice2).to.exist; + expect(invoice2.status).to.equal("paid"); + + expectProductAttached({ + customer: customer2, + product: pro, + }); + + expectFeaturesCorrect({ + customer: customer2, + product: pro, + }); + }); +}); diff --git a/server/tests/attach/checkout/checkout6.ts b/server/tests/attach/checkout/checkout6.ts new file mode 100644 index 000000000..44c7f12f5 --- /dev/null +++ b/server/tests/attach/checkout/checkout6.ts @@ -0,0 +1,158 @@ +import chalk from "chalk"; +import Stripe from "stripe"; + +import { AutumnInt } from "@/external/autumn/autumnCli.js"; +import { initCustomer } from "@/utils/scriptUtils/initCustomer.js"; +import { APIVersion, AppEnv, Organization } from "@autumn/shared"; +import { DrizzleCli } from "@/db/initDrizzle.js"; +import { setupBefore } from "tests/before.js"; +import { createProducts } from "tests/utils/productUtils.js"; +import { addPrefixToProducts } from "../utils.js"; +import { constructProduct } from "@/utils/scriptUtils/createTestProducts.js"; +import { constructFeatureItem } from "@/utils/scriptUtils/constructItem.js"; +import { TestFeature } from "tests/setup/v2Features.js"; +import { completeInvoiceCheckout } from "tests/utils/stripeUtils/completeInvoiceCheckout.js"; +import { expect } from "chai"; +import { expectProductAttached } from "tests/utils/expectUtils/expectProductAttached.js"; +import { expectFeaturesCorrect } from "tests/utils/expectUtils/expectFeaturesCorrect.js"; +import { expectAutumnError } from "tests/utils/expectUtils/expectErrUtils.js"; +import { getBasePrice } from "tests/utils/testProductUtils/testProductUtils.js"; + +export let pro = constructProduct({ + items: [ + constructFeatureItem({ + featureId: TestFeature.Messages, + includedUsage: 100, + }), + ], + type: "pro", +}); + +export let premium = constructProduct({ + items: [ + constructFeatureItem({ + featureId: TestFeature.Messages, + includedUsage: 250, + }), + ], + type: "premium", +}); + +const testCase = "checkout6"; +describe(`${chalk.yellowBright(`${testCase}: Testing invoice checkout via checkout endpoint`)}`, () => { + let customerId = testCase; + let autumn: AutumnInt = new AutumnInt({ version: APIVersion.v1_2 }); + let testClockId: string; + let db: DrizzleCli, org: Organization, env: AppEnv; + let stripeCli: Stripe; + let curUnix = new Date().getTime(); + + before(async function () { + await setupBefore(this); + const { autumnJs } = this; + db = this.db; + org = this.org; + env = this.env; + + stripeCli = this.stripeCli; + + addPrefixToProducts({ + products: [pro, premium], + prefix: testCase, + }); + + await createProducts({ + autumn, + products: [pro, premium], + customerId, + db, + orgId: org.id, + env, + }); + + const { testClockId: testClockId1 } = await initCustomer({ + autumn: autumnJs, + customerId, + db, + org, + env, + attachPm: "success", + }); + + testClockId = testClockId1!; + }); + + it("should attach pro product via invoice checkout", async function () { + const res = await autumn.checkout({ + customer_id: customerId, + product_id: pro.id, + invoice: true, + }); + + expect(res.url).to.exist; + + await completeInvoiceCheckout({ + url: res.url!, + }); + + const customer = await autumn.customers.get(customerId); + + expectProductAttached({ + customer, + product: pro, + }); + + expectFeaturesCorrect({ + customer, + product: pro, + }); + }); + + it("should have no URL returned if try to attach premium (with invoice true)", async function () { + await expectAutumnError({ + func: async () => { + await autumn.attach({ + customer_id: customerId, + product_id: premium.id, + invoice: true, + }); + }, + }); + + const res = await autumn.checkout({ + customer_id: customerId, + product_id: premium.id, + invoice: true, + }); + + expect(res.url).to.not.exist; + }); + + it("should attach premium product via invoice enable immediately", async function () { + const res = await autumn.attach({ + customer_id: customerId, + product_id: premium.id, + invoice: true, + enable_product_immediately: true, + }); + + const customer = await autumn.customers.get(customerId); + + expectProductAttached({ + customer, + product: premium, + }); + + expectFeaturesCorrect({ + customer, + product: premium, + }); + + const invoices = customer.invoices; + expect(invoices.length).to.equal(2); + expect(invoices[0].status).to.equal("draft"); + expect(invoices[0].total).to.equal( + getBasePrice({ product: premium }) - getBasePrice({ product: pro }) + ); // proration... + }); +}); diff --git a/server/tests/attach/checkout/checkout7.ts b/server/tests/attach/checkout/checkout7.ts new file mode 100644 index 000000000..f4950a57c --- /dev/null +++ b/server/tests/attach/checkout/checkout7.ts @@ -0,0 +1,141 @@ +import chalk from "chalk"; +import Stripe from "stripe"; + +import { AutumnInt } from "@/external/autumn/autumnCli.js"; +import { initCustomer } from "@/utils/scriptUtils/initCustomer.js"; +import { APIVersion, AppEnv, Organization } from "@autumn/shared"; +import { DrizzleCli } from "@/db/initDrizzle.js"; +import { setupBefore } from "tests/before.js"; +import { createProducts } from "tests/utils/productUtils.js"; +import { addPrefixToProducts } from "../utils.js"; +import { + constructProduct, + constructRawProduct, +} from "@/utils/scriptUtils/createTestProducts.js"; +import { + constructFeatureItem, + constructPrepaidItem, +} from "@/utils/scriptUtils/constructItem.js"; +import { TestFeature } from "tests/setup/v2Features.js"; +import { completeInvoiceCheckout } from "tests/utils/stripeUtils/completeInvoiceCheckout.js"; +import { expect } from "chai"; +import { expectProductAttached } from "tests/utils/expectUtils/expectProductAttached.js"; +import { expectFeaturesCorrect } from "tests/utils/expectUtils/expectFeaturesCorrect.js"; + +export let pro = constructProduct({ + items: [ + constructFeatureItem({ + featureId: TestFeature.Messages, + includedUsage: 100, + }), + ], + type: "pro", +}); + +export let addOn = constructRawProduct({ + id: "addOn", + items: [ + constructPrepaidItem({ + featureId: TestFeature.Messages, + billingUnits: 100, + price: 10, + isOneOff: true, + }), + ], +}); + +const testCase = "checkout7"; +describe(`${chalk.yellowBright(`${testCase}: Testing invoice checkout with one off product`)}`, () => { + let customerId = testCase; + let autumn: AutumnInt = new AutumnInt({ version: APIVersion.v1_2 }); + let testClockId: string; + let db: DrizzleCli, org: Organization, env: AppEnv; + let stripeCli: Stripe; + let curUnix = new Date().getTime(); + + before(async function () { + await setupBefore(this); + const { autumnJs } = this; + db = this.db; + org = this.org; + env = this.env; + + stripeCli = this.stripeCli; + + addPrefixToProducts({ + products: [pro, addOn], + prefix: testCase, + }); + + await createProducts({ + autumn, + products: [pro, addOn], + customerId, + db, + orgId: org.id, + env, + }); + + const { testClockId: testClockId1 } = await initCustomer({ + autumn: autumnJs, + customerId, + db, + org, + env, + attachPm: "success", + }); + + testClockId = testClockId1!; + }); + + it("should attach pro product, then add on product via invoice checkout", async function () { + await autumn.attach({ + customer_id: customerId, + product_id: pro.id, + }); + + const options = [ + { + quantity: 200, + feature_id: TestFeature.Messages, + }, + ]; + + const res2 = await autumn.checkout({ + customer_id: customerId, + product_id: addOn.id, + invoice: true, + options, + }); + + expect(res2.url).to.exist; + + await completeInvoiceCheckout({ + url: res2.url!, + }); + + const customer = await autumn.customers.get(customerId); + + expectProductAttached({ + customer, + product: addOn, + }); + + expectFeaturesCorrect({ + customer, + product: addOn, + otherProducts: [pro], + options, + }); + }); + + // it("should have no URL returned if try to attach add on (with invoice true)", async function () { + // const res = await autumn.checkout({ + // customer_id: customerId, + // product_id: addOn.id, + // invoice: true, + // }); + + // expect(res.url).to.not.exist; + // }); +}); diff --git a/server/tests/attach/others/others5.ts b/server/tests/attach/others/others5.ts index ae6539792..2323d8a24 100644 --- a/server/tests/attach/others/others5.ts +++ b/server/tests/attach/others/others5.ts @@ -12,12 +12,14 @@ const checkEntitledOnProduct = async ({ totalAllowance, finish = false, usageBased = false, + timeoutMs = 8000, }: { customerId: string; product: any; totalAllowance?: number; finish?: boolean; usageBased?: boolean; + timeoutMs?: number; }) => { // 1. Send events const allowance = totalAllowance || product.entitlements.metered1.allowance; @@ -35,7 +37,7 @@ const checkEntitledOnProduct = async ({ } await Promise.all(batchUpdates); - await timeout(8000); + await timeout(timeoutMs); let used = randomNum; // 2. Check entitled @@ -74,7 +76,7 @@ const checkEntitledOnProduct = async ({ ); } await Promise.all(batchUpdates2); - await timeout(8000); + await timeout(timeoutMs); used += allowance - randomNum; // 3. Check entitled again @@ -124,13 +126,13 @@ describe(`${chalk.yellowBright( }); }); - it("should have correct entitlements (free)", async function () { - await checkEntitledOnProduct({ - customerId: customerId, - product: products.free, - finish: true, - }); - }); + // it("should have correct entitlements (free)", async function () { + // await checkEntitledOnProduct({ + // customerId: customerId, + // product: products.free, + // finish: true, + // }); + // }); it("should attach pro", async function () { await AutumnCli.attach({ @@ -170,6 +172,7 @@ describe(`${chalk.yellowBright( product: products.oneTimeAddOnMetered1, finish: true, totalAllowance: curAllowance + oneTimeQuantity, + timeoutMs: 15000, }); }); }); @@ -231,7 +234,7 @@ describe(`${chalk.yellowBright( } await Promise.all(batchUpdates); - await timeout(14000); + await timeout(10000); const { allowed: allowed2, balanceObj: balanceObj2 }: any = await AutumnCli.entitled(customerId, features.metered1.id, true); diff --git a/server/tests/attach/others/others6.ts b/server/tests/attach/others/others6.ts index afc3d3b26..4b90730c3 100644 --- a/server/tests/attach/others/others6.ts +++ b/server/tests/attach/others/others6.ts @@ -93,7 +93,8 @@ describe(`${chalk.yellowBright(`${testCase}: Testing attach with customer ID and customer_id: internalCustomerId, entity_id: internalEntityId, product_id: pro.id, - invoice_only: true, + invoice: true, + enable_product_immediately: true, }); const customer = await autumn.customers.get(internalCustomerId); diff --git a/server/tests/utils/stripeUtils/completeInvoiceCheckout.ts b/server/tests/utils/stripeUtils/completeInvoiceCheckout.ts new file mode 100644 index 000000000..d449aafc2 --- /dev/null +++ b/server/tests/utils/stripeUtils/completeInvoiceCheckout.ts @@ -0,0 +1,144 @@ +import "dotenv/config"; + +import { Stripe } from "stripe"; +import puppeteer from "puppeteer-core"; +import Browserbase from "@browserbasehq/sdk"; + +import { Hyperbrowser } from "@hyperbrowser/sdk"; +import { timeout } from "../genUtils.js"; + +const client = new Hyperbrowser({ + apiKey: process.env.HYPERBROWSER_API_KEY, +}); + +export const completeInvoiceCheckout = async ({ + url, + isLocal = false, +}: { + url: string; + isLocal?: boolean; +}) => { + let browser; + + if (process.env.NODE_ENV === "development" && !isLocal) { + const session = await client.sessions.create(); + browser = await puppeteer.connect({ + browserWSEndpoint: session!.wsEndpoint, + defaultViewport: null, + }); + } else { + browser = await puppeteer.launch({ + headless: false, + executablePath: "/Applications/Chromium.app/Contents/MacOS/Chromium", + args: ["--no-sandbox", "--disable-setuid-sandbox"], + }); + } + + try { + const page = await browser.newPage(); + await page.setViewport({ width: 1280, height: 800 }); // Set standard desktop viewport size + await page.goto(url); + + // Wait for the payment element to load + + await page.waitForSelector("#payment-element", { timeout: 10000 }); + + // Wait a bit more for the iframe to fully load + await new Promise((resolve) => setTimeout(resolve, 3000)); + + // Try clicking on the payment element container to expand the accordion + + await page.click("#payment-element"); + + await new Promise((resolve) => setTimeout(resolve, 3000)); + + // Get the iframe containing the Stripe elements + const stripeFrame = await page.$("#payment-element iframe"); + if (!stripeFrame) { + throw new Error("Stripe iframe not found"); + } + + const frame = await stripeFrame.contentFrame(); + if (!frame) { + throw new Error("Could not access iframe content"); + } + + // Enter card number - try different possible selectors + try { + await frame.waitForSelector( + 'input[name="number"], input[data-elements-stable-field-name="cardNumber"], input[placeholder*="1234"], input[aria-label*="Card number"]', + { timeout: 2000 } + ); + const cardNumberInput = await frame.$( + 'input[name="number"], input[data-elements-stable-field-name="cardNumber"], input[placeholder*="1234"], input[aria-label*="Card number"]' + ); + if (cardNumberInput) { + await cardNumberInput.click(); + await cardNumberInput.type("4242424242424242"); + } + } catch (error) { + console.log("Could not find card number input:", error); + } + + // Enter expiry date + try { + await frame.waitForSelector( + 'input[name="expiry"], input[data-elements-stable-field-name="cardExpiry"], input[placeholder*="MM"], input[aria-label*="expir"]', + { timeout: 2000 } + ); + const expiryInput = await frame.$( + 'input[name="expiry"], input[data-elements-stable-field-name="cardExpiry"], input[placeholder*="MM"], input[aria-label*="expir"]' + ); + if (expiryInput) { + await expiryInput.click(); + await expiryInput.type("1227"); + } + } catch (error) { + console.log("Could not find expiry input:", error); + } + + // Enter CVC + try { + await frame.waitForSelector( + 'input[name="cvc"], input[data-elements-stable-field-name="cardCvc"], input[placeholder*="CVC"], input[aria-label*="CVC"]', + { timeout: 2000 } + ); + const cvcInput = await frame.$( + 'input[name="cvc"], input[data-elements-stable-field-name="cardCvc"], input[placeholder*="CVC"], input[aria-label*="CVC"]' + ); + if (cvcInput) { + await cvcInput.click(); + await cvcInput.type("123"); + } + } catch (error) { + console.log("Could not find CVC input:", error); + } + + // Enter postal code + try { + await frame.waitForSelector( + 'input[name="postalCode"], input[data-elements-stable-field-name="postalCode"], input[placeholder*="12345"], input[aria-label*="ZIP"]', + { timeout: 2000 } + ); + const postalInput = await frame.$( + 'input[name="postalCode"], input[data-elements-stable-field-name="postalCode"], input[placeholder*="12345"], input[aria-label*="ZIP"]' + ); + if (postalInput) { + await postalInput.click(); + await postalInput.type("12345"); + } + } catch (error) { + console.log("Could not find postal code input:", error); + } + + // Wait a bit for all inputs to be processed + await new Promise((resolve) => setTimeout(resolve, 2000)); + + const submitButton = await page.$(".SubmitButton-IconContainer"); + await submitButton?.evaluate((b: any) => (b as HTMLElement).click()); + await timeout(20000); + } finally { + // always close browser + await browser.close(); + } +}; diff --git a/shared/db/auth-relations.ts b/shared/db/auth-relations.ts index d5048222a..f4744df1d 100644 --- a/shared/db/auth-relations.ts +++ b/shared/db/auth-relations.ts @@ -1,5 +1,12 @@ import { relations } from "drizzle-orm"; -import { user } from "./auth-schema.js"; +import { member, user } from "./auth-schema.js"; import { organizations } from "../models/orgModels/orgTable.js"; export const userRelations = relations(user, ({ many }) => ({})); + +export const memberRelations = relations(member, ({ one }) => ({ + organization: one(organizations, { + fields: [member.organizationId], + references: [organizations.id], + }), +})); diff --git a/shared/db/auth-schema.ts b/shared/db/auth-schema.ts index a420a5837..f5f5a5b03 100644 --- a/shared/db/auth-schema.ts +++ b/shared/db/auth-schema.ts @@ -7,6 +7,7 @@ import { foreignKey, } from "drizzle-orm/pg-core"; import { organizations } from "./schema.js"; +import { relations } from "drizzle-orm"; export const user = pgTable( "user", diff --git a/shared/db/schema.ts b/shared/db/schema.ts index 6ce6d4e4e..3bcda8fd0 100644 --- a/shared/db/schema.ts +++ b/shared/db/schema.ts @@ -79,7 +79,7 @@ import { member, invitation, } from "./auth-schema.js"; -import { userRelations } from "./auth-relations.js"; +import { userRelations, memberRelations } from "./auth-relations.js"; export { // Tables @@ -140,4 +140,5 @@ export { rolloverRelations, // Auth Relations userRelations, + memberRelations, }; diff --git a/shared/models/attachModels/attachBody.ts b/shared/models/attachModels/attachBody.ts index 6d14dfd3c..e80597ff3 100644 --- a/shared/models/attachModels/attachBody.ts +++ b/shared/models/attachModels/attachBody.ts @@ -44,6 +44,7 @@ export const AttachBodySchema = z checkout_session_params: z.any().optional(), reward: z.string().optional(), invoice: z.boolean().optional(), + enable_product_immediately: z.boolean().optional(), }) .refine( (data) => { diff --git a/shared/models/attachModels/attachEnums/AttachConfig.ts b/shared/models/attachModels/attachEnums/AttachConfig.ts index 560ca9b19..bdd1dd27e 100644 --- a/shared/models/attachModels/attachEnums/AttachConfig.ts +++ b/shared/models/attachModels/attachEnums/AttachConfig.ts @@ -8,6 +8,7 @@ export enum ProrationBehavior { export interface AttachConfig { onlyCheckout: boolean; + invoiceCheckout: boolean; carryUsage: boolean; // Whether to carry over existing usages branch: AttachBranch; proration: ProrationBehavior; diff --git a/shared/models/cusModels/cusModels.ts b/shared/models/cusModels/cusModels.ts index 66e41459c..30f72e3d8 100644 --- a/shared/models/cusModels/cusModels.ts +++ b/shared/models/cusModels/cusModels.ts @@ -33,6 +33,7 @@ export const CustomerDataSchema = z.object({ email: z.string().nullish(), fingerprint: z.string().nullish(), metadata: z.record(z.any()).nullish().default({}), + stripe_id: z.string().nullish(), }); export const CustomerResponseSchema = CustomerSchema.omit({ diff --git a/shared/models/productV2Models/productItemModels/productItemModels.ts b/shared/models/productV2Models/productItemModels/productItemModels.ts index 40eed0c0f..72dd7128d 100644 --- a/shared/models/productV2Models/productItemModels/productItemModels.ts +++ b/shared/models/productV2Models/productItemModels/productItemModels.ts @@ -94,8 +94,14 @@ export const LimitedItemSchema = ProductItemSchema.extend({ included_usage: z.number(), }); +export const FrontendProductItem = ProductItemSchema.extend({ + isPrice: z.boolean(), + isVariable: z.boolean().nullish(), +}); + export type ProductItem = z.infer; export type LimitedItem = z.infer; export type ProductItemConfig = z.infer; export type PriceTier = z.infer; export type RolloverConfig = z.infer; +export type FrontendProductItem = z.infer; diff --git a/vite/src/components/autumn/checkout-dialog.tsx b/vite/src/components/autumn/checkout-dialog.tsx index 5a90d5b8e..a2ce9d12c 100644 --- a/vite/src/components/autumn/checkout-dialog.tsx +++ b/vite/src/components/autumn/checkout-dialog.tsx @@ -351,13 +351,15 @@ const PrepaidItem = ({ const disableSelection = scenario === "renew"; return ( -
-
-

{item.feature?.name}

+
+
+

+ {item.feature?.name} +

-

+

{item.display?.primary_text} {item.display?.secondary_text}

diff --git a/vite/src/components/general/SelectType.tsx b/vite/src/components/general/SelectType.tsx new file mode 100644 index 000000000..73fc434ca --- /dev/null +++ b/vite/src/components/general/SelectType.tsx @@ -0,0 +1,42 @@ +import { cn } from "@/lib/utils"; + +export const SelectType = ({ + title, + description, + icon, + isSelected, + onClick, + disabled = false, +}: { + title: string; + description: string; + icon: React.ReactNode; + isSelected: boolean; + onClick: () => void; + disabled?: boolean; +}) => { + return ( + + ); +}; diff --git a/vite/src/components/general/ToggleButton.tsx b/vite/src/components/general/ToggleButton.tsx index 369f1698c..1704af6b6 100644 --- a/vite/src/components/general/ToggleButton.tsx +++ b/vite/src/components/general/ToggleButton.tsx @@ -13,14 +13,16 @@ export const ToggleButton = ({ className, disabled, infoContent, + switchClassName, }: { value: boolean; setValue: (value: boolean) => void; tooltipContent?: string; - buttonText?: string; + buttonText?: string | React.ReactNode; className?: string; disabled?: boolean; infoContent?: string; + switchClassName?: string; }) => { const MainButton = ( ); diff --git a/vite/src/components/general/modal-components/DialogContentWrapper.tsx b/vite/src/components/general/modal-components/DialogContentWrapper.tsx index 0637f743c..b3dc688ac 100644 --- a/vite/src/components/general/modal-components/DialogContentWrapper.tsx +++ b/vite/src/components/general/modal-components/DialogContentWrapper.tsx @@ -15,8 +15,9 @@ export const CustomDialogContent = ({ return ( diff --git a/vite/src/components/general/modal-components/InfoTooltip.tsx b/vite/src/components/general/modal-components/InfoTooltip.tsx index c1476f321..217658195 100644 --- a/vite/src/components/general/modal-components/InfoTooltip.tsx +++ b/vite/src/components/general/modal-components/InfoTooltip.tsx @@ -8,13 +8,15 @@ import { InfoIcon } from "lucide-react"; export const InfoTooltip = ({ children, + className, ...props }: { children: React.ReactNode; + className?: string; } & TooltipContentProps) => { return ( - + diff --git a/vite/src/components/ui/input.tsx b/vite/src/components/ui/input.tsx index 7e8626b54..58c01205e 100644 --- a/vite/src/components/ui/input.tsx +++ b/vite/src/components/ui/input.tsx @@ -11,10 +11,6 @@ interface InputProps extends React.ComponentProps<"input"> { const Input = React.forwardRef( ({ className, type, startContent, endContent, variant, ...props }, ref) => { const hasAdornment = startContent || endContent; - const [isFocused, setIsFocused] = React.useState(false); - - const handleFocus = () => setIsFocused(true); - const handleBlur = () => setIsFocused(false); // const gradientBg = // "bg-[linear-gradient(180deg,white,theme(colors.stone.50))]"; @@ -26,15 +22,13 @@ const Input = React.forwardRef( {hasAdornment ? (
@@ -46,11 +40,9 @@ const Input = React.forwardRef( p-2 `, - className, + className )} ref={ref} - onFocus={handleFocus} - onBlur={handleBlur} {...props} />
@@ -70,7 +62,7 @@ const Input = React.forwardRef( variant === "destructive" ? `focus-visible:border-red-400 focus-visible:shadow-[0_0_2px_1px_rgba(248,113,113,0.25)]` : `focus-visible:shadow-focus`, - className, + className )} ref={ref} {...props} @@ -78,7 +70,7 @@ const Input = React.forwardRef( )} ); - }, + } ); Input.displayName = "Input"; diff --git a/vite/src/utils/product/getItemType.ts b/vite/src/utils/product/getItemType.ts index b544faf7c..6545fbd0d 100644 --- a/vite/src/utils/product/getItemType.ts +++ b/vite/src/utils/product/getItemType.ts @@ -8,7 +8,7 @@ export const isEmptyItem = (item: ProductItem) => { export const isFeatureItem = (item: ProductItem) => { return ( // notNullish(item.feature_id) && - (nullish(item.price) || item.price == 0) && nullish(item.tiers) + nullish(item.price) && nullish(item.tiers) ); }; diff --git a/vite/src/utils/product/product-item/validateProductItem.ts b/vite/src/utils/product/product-item/validateProductItem.ts index 5dffaf5a6..8b5dab55d 100644 --- a/vite/src/utils/product/product-item/validateProductItem.ts +++ b/vite/src/utils/product/product-item/validateProductItem.ts @@ -2,6 +2,7 @@ import { invalidNumber, notNullish, nullish } from "@/utils/genUtils"; import { Feature, FeatureUsageType, + FrontendProductItem, Infinite, ProductItem, ProductItemInterval, @@ -17,7 +18,7 @@ export const validateProductItem = ({ // show, features, }: { - item: ProductItem; + item: FrontendProductItem; // show: any; features: Feature[]; }) => { @@ -31,11 +32,22 @@ export const validateProductItem = ({ item.interval = null; } + if (item.isPrice && item.isVariable && !item.feature_id) { + toast.error("Please select a feature"); + return null; + } + if (notNullish(item.price)) { if (invalidNumber(item.price)) { toast.error("Please enter a valid price amount"); return null; } + + if (item.price === 0) { + toast.error("Price should be greater than 0"); + return null; + } + item.price = parseFloat(item.price!.toString()); } @@ -45,17 +57,51 @@ export const validateProductItem = ({ item.included_usage = Number(item.included_usage); } + if (isFeaturePriceItem(item) && nullish(item.usage_model)) { + toast.error("Please select a usage model"); + return null; + } + //if both item.tiers and item.price are set, set item.price to null if (item.tiers && item.price) { item.price = null; } // Usage/Feature item validation (when tiers are set) + if (item.tiers) { let previousTo = 0; - for (let i = 0; i < item.tiers.length; i++) { - const tier = item.tiers[i]; + const allFree = item.tiers.every((tier) => tier.amount == 0); + + if (allFree) { + if (item.tiers.length == 1) { + toast.error("Price should be greater than 0"); + } else { + toast.error("Should have at least one tier with price greater than 0"); + } + return null; + } + + const freeTier = + item.tiers.length > 0 && item.tiers[0].amount == 0 ? item.tiers[0] : null; + + // const includedUsage = parseFloat(item.included_usage?.toString() || "0"); + + let finalTiers = item.tiers; + + if (freeTier) { + finalTiers = finalTiers.slice(1); + item.included_usage = parseFloat(freeTier.to.toString() || "0"); + + finalTiers = finalTiers.map((tier) => { + tier.amount -= freeTier.amount; + return tier; + }); + } + + for (let i = 0; i < finalTiers.length; i++) { + const tier = finalTiers[i]; // Check if amount is actually a number if (typeof tier.amount !== "number") { @@ -88,15 +134,24 @@ export const validateProductItem = ({ } // Ensure tiers are in ascending order - if (tier.to <= previousTo) { + if (tier.to < previousTo) { toast.error("Tiers must be in ascending order"); return null; } + if (tier.to == previousTo) { + toast.error(`tier ${i + 1} should have a greater 'to'`); + return null; + } + previousTo = tier.to; } + + item.tiers = finalTiers; } + console.log("Final tiers:", item.tiers); + // Validate billing units if (item.billing_units && invalidNumber(item.billing_units)) { toast.error("Please enter valid billing units"); diff --git a/vite/src/utils/product/productItemUtils.ts b/vite/src/utils/product/productItemUtils.ts index 0c11d4e3b..d912e6295 100644 --- a/vite/src/utils/product/productItemUtils.ts +++ b/vite/src/utils/product/productItemUtils.ts @@ -100,3 +100,16 @@ export const shouldShowProrationConfig = ({ } return false; }; + +export const itemsHaveSameInterval = ({ + item1, + item2, +}: { + item1: ProductItem; + item2: ProductItem; +}) => { + return ( + item1.interval == item2.interval && + (item1.interval_count || 1) == (item2.interval_count || 1) + ); +}; diff --git a/vite/src/views/customers/customer/UpdateCustomerDialog.tsx b/vite/src/views/customers/customer/UpdateCustomerDialog.tsx index 6f4d37ef9..bb5dbd40b 100644 --- a/vite/src/views/customers/customer/UpdateCustomerDialog.tsx +++ b/vite/src/views/customers/customer/UpdateCustomerDialog.tsx @@ -1,7 +1,5 @@ import { DialogFooter } from "@/components/ui/dialog"; - -import { getOriginalCouponId } from "@/utils/product/couponUtils"; -import { getBackendErr } from "@/utils/genUtils"; +import { getBackendErr, navigateTo } from "@/utils/genUtils"; import { Reward, CreateCustomer, Customer } from "@autumn/shared"; import { useEffect, useState } from "react"; import { toast } from "sonner"; @@ -14,6 +12,7 @@ import { useAxiosInstance } from "@/services/useAxiosInstance"; import { useEnv } from "@/utils/envUtils"; import { CustomerConfig } from "./CustomerConfig"; import { CusService } from "@/services/customers/CusService"; +import { useNavigate } from "react-router"; const UpdateCustomerDialog = ({ selectedCustomer, @@ -30,6 +29,7 @@ const UpdateCustomerDialog = ({ const [loading, setLoading] = useState(false); const env = useEnv(); const axiosInstance = useAxiosInstance({ env }); + const navigate = useNavigate(); useEffect(() => { setCustomer(selectedCustomer); @@ -42,6 +42,7 @@ const UpdateCustomerDialog = ({ axios: axiosInstance, customer_id: selectedCustomer.id || selectedCustomer.internal_id, data: { + id: customer.id || undefined, name: customer.name || null, email: customer.email || null, fingerprint: customer.fingerprint || null, @@ -51,6 +52,10 @@ const UpdateCustomerDialog = ({ toast.success(`Successfully updated customer`); setOpen(false); await cusMutate(); + + if (customer.id != selectedCustomer.id) { + navigateTo(`/customers/${customer.id}`, navigate, env); + } } catch (error) { toast.error(getBackendErr(error, "Failed to update customer")); } finally { diff --git a/vite/src/views/customers/customer/customer-sidebar/customer-details.tsx b/vite/src/views/customers/customer/customer-sidebar/customer-details.tsx index cbc3f51ce..83fcea525 100644 --- a/vite/src/views/customers/customer/customer-sidebar/customer-details.tsx +++ b/vite/src/views/customers/customer/customer-sidebar/customer-details.tsx @@ -32,7 +32,15 @@ export const CustomerDetails = ({ {customer.id} ) : ( - N/A + )}
@@ -103,7 +111,7 @@ export const CustomerDetails = ({ > diff --git a/vite/src/views/customers/customer/product/components/AttachModal.tsx b/vite/src/views/customers/customer/product/components/AttachModal.tsx index 56f22e4f6..f57744588 100644 --- a/vite/src/views/customers/customer/product/components/AttachModal.tsx +++ b/vite/src/views/customers/customer/product/components/AttachModal.tsx @@ -31,6 +31,7 @@ import { cn } from "@/lib/utils"; import { Separator } from "@/components/ui/separator"; import { AttachInfo } from "./attach-preview/AttachInfo"; import { getAttachBody } from "./attachProductUtils"; +import { InvoiceCustomerButton } from "./InvoiceCustomerButton"; export const AttachModal = ({ open, @@ -118,8 +119,15 @@ export const AttachModal = ({ return "Charge Customer"; }; - const handleAttachClicked = async (useInvoice: boolean) => { - const setLoading = useInvoice ? setInvoiceLoading : setCheckoutLoading; + const handleAttachClicked = async ({ + useInvoice, + enableProductImmediately, + setLoading, + }: { + useInvoice: boolean; + enableProductImmediately?: boolean; + setLoading: (loading: boolean) => void; + }) => { const cusId = getCusId(); for (const option of options) { @@ -145,6 +153,7 @@ export const AttachModal = ({ optionsInput: options, attachState, useInvoice, + enableProductImmediately, successUrl: `${import.meta.env.VITE_FRONTEND_URL}${redirectUrl}`, version: version || product.version, }); @@ -155,9 +164,8 @@ export const AttachModal = ({ window.open(data.checkout_url, "_blank"); } else if (data.invoice) { window.open(getStripeInvoiceLink(data.invoice), "_blank"); - } else { - navigateTo(`/customers/${cusId}`, navigation, env); } + navigateTo(`/customers/${cusId}`, navigation, env); toast.success(data.message || "Successfully attached product"); setOpen(false); @@ -186,7 +194,7 @@ export const AttachModal = ({ const mainWidth = "w-lg"; return ( - +
{invoiceAllowed() && ( - + + // )} diff --git a/vite/src/views/customers/customer/product/components/InvoiceCustomerButton.tsx b/vite/src/views/customers/customer/product/components/InvoiceCustomerButton.tsx new file mode 100644 index 000000000..8eb952b83 --- /dev/null +++ b/vite/src/views/customers/customer/product/components/InvoiceCustomerButton.tsx @@ -0,0 +1,103 @@ +import FieldLabel from "@/components/general/modal-components/FieldLabel"; +import { Button } from "@/components/ui/button"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { AttachBranch, AttachFunction } from "@autumn/shared"; +import { ArrowUpRightFromSquare } from "lucide-react"; +import { useState } from "react"; + +export const InvoiceCustomerButton = ({ + handleAttachClicked, + preview, +}: { + handleAttachClicked: any; + preview?: any; +}) => { + const [immediateLoading, setImmediateLoading] = useState(false); + const [afterPaymentLoading, setAfterPaymentLoading] = useState(false); + const buttonsDisabled = immediateLoading || afterPaymentLoading; + + const allowedBranches = [ + AttachBranch.New, + AttachBranch.MainIsTrial, + AttachBranch.MainIsFree, + AttachBranch.OneOff, + AttachBranch.AddOn, + ]; + + // const immediateDisabled = !allowedBranches.includes(preview?.branch); + + console.log("Preview:", preview); + + return ( + + + + + +
+
+

Enable Product Immediately

+

+ This will enable the product for the customer immediately, and + redirect you to Stripe to finalize the invoice +

+ +
+
+ {preview?.func == AttachFunction.CreateCheckout && ( +
+
+

Enable Product After Payment

+

+ This will generate an invoice link for the customer, and enable + the product after they pay the invoice +

+ +
+
+ )} +
+
+ ); +}; diff --git a/vite/src/views/customers/customer/product/components/attachProductUtils.ts b/vite/src/views/customers/customer/product/components/attachProductUtils.ts index 0f98b5a57..767d1ed9a 100644 --- a/vite/src/views/customers/customer/product/components/attachProductUtils.ts +++ b/vite/src/views/customers/customer/product/components/attachProductUtils.ts @@ -13,6 +13,7 @@ export const getAttachBody = ({ entityId, optionsInput, useInvoice, + enableProductImmediately = true, successUrl, version, }: { @@ -22,6 +23,7 @@ export const getAttachBody = ({ entityId: string; optionsInput?: FeatureOptions[]; useInvoice?: boolean; + enableProductImmediately?: boolean; successUrl?: string; version?: number; }) => { @@ -47,7 +49,14 @@ export const getAttachBody = ({ ...customData, free_trial: isCustom ? product.free_trial || undefined : undefined, - invoice_only: useInvoice, + invoice: useInvoice, + enable_product_immediately: useInvoice + ? enableProductImmediately + : undefined, + + force_checkout: + useInvoice && enableProductImmediately === false ? true : undefined, + success_url: successUrl, version: version ? Number(version) : undefined, }; diff --git a/vite/src/views/features/metered-features/FeatureConfig.tsx b/vite/src/views/features/metered-features/FeatureConfig.tsx index b8a81b283..bd0097ebb 100644 --- a/vite/src/views/features/metered-features/FeatureConfig.tsx +++ b/vite/src/views/features/metered-features/FeatureConfig.tsx @@ -15,8 +15,9 @@ import { TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; +import { SelectFeatureUsageType } from "./SelectFeatureUsageType"; +import { notNullish, nullish } from "@/utils/genUtils"; import { SelectFeatureType } from "./SelectFeatureType"; -import { notNullish } from "@/utils/genUtils"; export function FeatureConfig({ feature, @@ -69,98 +70,33 @@ export function FeatureConfig({ ); const [idChanged, setIdChanged] = useState(!!feature.id); - // useEffect(() => { - // setFeature({ - // ...feature, - // name: fields.name, - // id: fields.id, - // type: null, - // config: meteredConfig, - // }); - // }, [meteredConfig, fields]); + const showNameAndId = () => { + if (nullish(feature.type)) { + return false; + } + + if ( + feature.type === FeatureType.Metered && + nullish(feature.config?.usage_type) + ) { + return false; + } + + return true; + }; return (
- {/* - - Metered - Boolean - -

- {featureType == FeatureType.Metered && - "A usage-based feature that you want to track"} - {featureType == FeatureType.Boolean && - "A feature flag that can be either enabled or disabled"} -

-
*/} - +
+ Features are the parts of your application that customers get access to + when purchasing a product +
- {/* {featureType === FeatureType.Metered && ( -
-
- { - setMeteredConfig({ - ...meteredConfig, - usage_type: value as FeatureUsageType, - }); - }} - > - - - - Single Use - - - - Continuous Use - - -

- {meteredConfig.usage_type === FeatureUsageType.Continuous - ? "For features used on an ongoing basis, like 'seats' or 'storage'" - : "For features that are consumed and refilled like 'credits' or 'API calls'"} - - - - - -

- Single use features can have a reset period, to refill a - balance every month, day etc. Existing usage is also - typically reset on upgrades. -
-
- Continuous use features don't have a reset period. They - can be prorated (eg, if a seat is purchased halfway during - the month, it'll cost half the price). -

- - -

-
-
-
- )} */} - {notNullish(feature.type) && ( + {feature.type == FeatureType.Metered && ( + + )} + + {showNameAndId() && ( <>
@@ -351,3 +287,86 @@ export const FilterInput = ({
); }; + +{ + /* {featureType === FeatureType.Metered && ( +
+
+ { + setMeteredConfig({ + ...meteredConfig, + usage_type: value as FeatureUsageType, + }); + }} + > + + + + Single Use + + + + Continuous Use + + +

+ {meteredConfig.usage_type === FeatureUsageType.Continuous + ? "For features used on an ongoing basis, like 'seats' or 'storage'" + : "For features that are consumed and refilled like 'credits' or 'API calls'"} + + + + + +

+ Single use features can have a reset period, to refill a + balance every month, day etc. Existing usage is also + typically reset on upgrades. +
+
+ Continuous use features don't have a reset period. They + can be prorated (eg, if a seat is purchased halfway during + the month, it'll cost half the price). +

+ + +

+
+
+
+ )} */ +} + +{ + /* + + Metered + Boolean + +

+ {featureType == FeatureType.Metered && + "A usage-based feature that you want to track"} + {featureType == FeatureType.Boolean && + "A feature flag that can be either enabled or disabled"} +

+
*/ +} diff --git a/vite/src/views/features/metered-features/SelectFeatureType.tsx b/vite/src/views/features/metered-features/SelectFeatureType.tsx index 10ec73bfa..206769a50 100644 --- a/vite/src/views/features/metered-features/SelectFeatureType.tsx +++ b/vite/src/views/features/metered-features/SelectFeatureType.tsx @@ -1,46 +1,14 @@ +import FieldLabel from "@/components/general/modal-components/FieldLabel"; +import { SelectType } from "@/components/general/SelectType"; import { APIFeatureType, CreateFeature, FeatureType, FeatureUsageType, } from "@autumn/shared"; -import { Clock, ToggleLeft, Zap } from "lucide-react"; +import { Zap, Clock, ArrowUp01, Flag } from "lucide-react"; import { defaultMeteredConfig } from "./defaultFeatureConfig"; -import FieldLabel from "@/components/general/modal-components/FieldLabel"; -const SelectType = ({ - title, - description, - icon, - isSelected, - onClick, -}: { - title: string; - description: string; - icon: React.ReactNode; - isSelected: boolean; - onClick: () => void; -}) => { - return ( -
-
- - {title} - -
{icon}
-
-

{description}

-
- ); -}; export const SelectFeatureType = ({ feature, setFeature, @@ -69,35 +37,45 @@ export const SelectFeatureType = ({ }; return (
- Select Feature Type -
+ Feature Type +
} - isSelected={ - featureType === FeatureType.Metered && - usageType === FeatureUsageType.Single - } - onClick={() => setFeatureType(APIFeatureType.SingleUsage)} - /> - } - isSelected={ - featureType === FeatureType.Metered && - usageType === FeatureUsageType.Continuous - } - onClick={() => setFeatureType(APIFeatureType.ContinuousUse)} + title="Metered" + description="A usage-based feature that you want to track" + icon={} + isSelected={featureType === FeatureType.Metered} + onClick={() => { + const curConfig = feature.config; + setFeature({ + ...feature, + type: FeatureType.Metered, + config: { + ...defaultMeteredConfig, + usage_type: curConfig?.usage_type ?? null, + }, + }); + }} /> } + description="A feature flag that can be either enabled or disabled" + icon={} isSelected={featureType === FeatureType.Boolean} - onClick={() => setFeatureType(APIFeatureType.Boolean)} + onClick={() => + setFeature({ + ...feature, + type: FeatureType.Boolean, + config: undefined, + }) + } /> + {/* } + isSelected={featureType === FeatureType.Boolean} + onClick={() => setFeatureType(APIFeatureType.Boolean)} + /> */}
); diff --git a/vite/src/views/features/metered-features/SelectFeatureUsageType.tsx b/vite/src/views/features/metered-features/SelectFeatureUsageType.tsx new file mode 100644 index 000000000..ae2d553cf --- /dev/null +++ b/vite/src/views/features/metered-features/SelectFeatureUsageType.tsx @@ -0,0 +1,72 @@ +import { + APIFeatureType, + CreateFeature, + FeatureType, + FeatureUsageType, +} from "@autumn/shared"; +import { Clock, ToggleLeft, Zap } from "lucide-react"; +import { defaultMeteredConfig } from "./defaultFeatureConfig"; +import FieldLabel from "@/components/general/modal-components/FieldLabel"; +import { SelectType } from "@/components/general/SelectType"; + +export const SelectFeatureUsageType = ({ + feature, + setFeature, +}: { + feature: CreateFeature; + setFeature: any; +}) => { + const featureType = feature.type; + const usageType = feature.config?.usage_type; + + const setFeatureType = (type: APIFeatureType) => { + // 1. If type is boolean + if (type === APIFeatureType.Boolean) { + setFeature({ + ...feature, + type: APIFeatureType.Boolean, + config: undefined, + }); + } else { + setFeature({ + ...feature, + type: FeatureType.Metered, + config: { ...defaultMeteredConfig, usage_type: type }, + }); + } + }; + return ( +
+ Usage Type +
+ } + isSelected={ + featureType === FeatureType.Metered && + usageType === FeatureUsageType.Single + } + onClick={() => setFeatureType(APIFeatureType.SingleUsage)} + /> + } + isSelected={ + featureType === FeatureType.Metered && + usageType === FeatureUsageType.Continuous + } + onClick={() => setFeatureType(APIFeatureType.ContinuousUse)} + /> + {/* } + isSelected={featureType === FeatureType.Boolean} + onClick={() => setFeatureType(APIFeatureType.Boolean)} + /> */} +
+
+ ); +}; diff --git a/vite/src/views/features/utils/defaultFeature.ts b/vite/src/views/features/utils/defaultFeature.ts index 9a5d4e004..d700f7f49 100644 --- a/vite/src/views/features/utils/defaultFeature.ts +++ b/vite/src/views/features/utils/defaultFeature.ts @@ -6,7 +6,7 @@ export const getDefaultFeature = (entityCreate?: boolean): any => { return { type: FeatureType.Metered, config: { - defaultMeteredConfig, + ...defaultMeteredConfig, usage_type: FeatureUsageType.Continuous, }, name: "", diff --git a/vite/src/views/main-sidebar/org-dropdown/hooks/useMemberships.tsx b/vite/src/views/main-sidebar/org-dropdown/hooks/useMemberships.tsx index b3fec796e..12bc96b90 100644 --- a/vite/src/views/main-sidebar/org-dropdown/hooks/useMemberships.tsx +++ b/vite/src/views/main-sidebar/org-dropdown/hooks/useMemberships.tsx @@ -11,31 +11,31 @@ export const useMemberships = () => { url: "/organization/members", }); - const { data: session } = useSession(); - const { data: orgs } = useListOrganizations(); + // const { data: session } = useSession(); + // const { data: orgs } = useListOrganizations(); - const handleRemovedFromOrg = async () => { - const inOrg = orgs?.find( - (org: any) => org.id === session?.session?.activeOrganizationId, - ); + // const handleRemovedFromOrg = async () => { + // const inOrg = orgs?.find( + // (org: any) => org.id === session?.session?.activeOrganizationId, + // ); - if (!inOrg) { - if (orgs && orgs.length > 0) { - await authClient.organization.setActive({ - organizationId: orgs[0].id, - }); - } else { - const { data, error } = await authClient.revokeSessions(); - console.log("Revoked sessions", data, error); - } - window.location.reload(); - } - }; + // if (!inOrg) { + // if (orgs && orgs.length > 0) { + // await authClient.organization.setActive({ + // organizationId: orgs[0].id, + // }); + // } else { + // const { data, error } = await authClient.revokeSessions(); + // console.log("Revoked sessions", data, error); + // } + // window.location.reload(); + // } + // }; - useEffect(() => { - if (!orgs) return; - handleRemovedFromOrg(); - }, [orgs]); + // useEffect(() => { + // if (!orgs) return; + // handleRemovedFromOrg(); + // }, [orgs]); return { memberships: data?.memberships || [], diff --git a/vite/src/views/onboarding2/model-pricing/SelectEditProduct.tsx b/vite/src/views/onboarding2/model-pricing/SelectEditProduct.tsx index 053a84e85..9f3bd1b50 100644 --- a/vite/src/views/onboarding2/model-pricing/SelectEditProduct.tsx +++ b/vite/src/views/onboarding2/model-pricing/SelectEditProduct.tsx @@ -48,7 +48,12 @@ export const SelectEditProduct = () => { return ( setProduct(p)} + onClick={() => { + setProduct(p); + setQueryStates({ + productId: p.id, + }); + }} className="flex items-center justify-between group" > {p.name} diff --git a/vite/src/views/products/product/prices/CreateFixedPrice.tsx b/vite/src/views/products/product/prices/CreateFixedPrice.tsx index 563b85f2a..cb1cac6ea 100644 --- a/vite/src/views/products/product/prices/CreateFixedPrice.tsx +++ b/vite/src/views/products/product/prices/CreateFixedPrice.tsx @@ -21,18 +21,8 @@ import { getBackendErr, getRedirectUrl } from "@/utils/genUtils"; import { useEnv } from "@/utils/envUtils"; import { useNavigate } from "react-router"; -function CreateFixedPrice({ - config, - setConfig, - show, - setShow, -}: { - config: any; - setConfig: (config: any) => void; - show: any; - setShow: (show: any) => void; -}) { - const { item, selectedIndex } = useProductItemContext(); +function CreateFixedPrice() { + const { item, setItem, selectedIndex } = useProductItemContext(); const { org, product, counts, hasChanges } = useProductContext(); const [copyLoading, setCopyLoading] = useState(false); const axiosInstance = useAxiosInstance(); @@ -125,23 +115,25 @@ function CreateFixedPrice({ return (
{/*

Rates

*/} -
-
+
+
Fixed Price
{ - setConfig({ ...config, price: e.target.value }); + setItem({ ...item, price: e.target.value }); }} placeholder="30.00" type="number" step="any" - className="h-full !text-lg min-w-36" + className="min-w-36" + endContent={ + + {org?.default_currency?.toUpperCase() || "USD"} + + } /> - - {org?.default_currency?.toUpperCase() || "USD"} -
diff --git a/vite/src/views/products/product/product-item/CreateProductItem.tsx b/vite/src/views/products/product/product-item/CreateProductItem.tsx index 0a54c2221..5b64b36a6 100644 --- a/vite/src/views/products/product/product-item/CreateProductItem.tsx +++ b/vite/src/views/products/product/product-item/CreateProductItem.tsx @@ -2,22 +2,30 @@ import { Button } from "@/components/ui/button"; import { Dialog, DialogTrigger } from "@/components/ui/dialog"; import { useEffect, useState } from "react"; -import { ProductItemContext } from "./ProductItemContext"; +import { + ProductItemContext, + useProductItemContext, +} from "./ProductItemContext"; import { ProductItemInterval, ProductItem, CreateFeature as CreateFeatureType, + FrontendProductItem, + Infinite, } from "@autumn/shared"; import { useProductContext } from "../ProductContext"; import { validateProductItem } from "@/utils/product/product-item/validateProductItem"; -import { useAxiosInstance } from "@/services/useAxiosInstance"; import { CreateItemDialogContent } from "./create-product-item/CreateItemDialogContent"; import { Plus } from "lucide-react"; import { useSteps } from "./useSteps"; import { CreateItemStep } from "./utils/CreateItemStep"; -import { isFeatureItem } from "@/utils/product/getItemType"; +import { isFeatureItem, isFeaturePriceItem } from "@/utils/product/getItemType"; +import { emptyPriceItem } from "./create-product-item/defaultItemConfigs"; +import { itemsHaveSameInterval } from "@/utils/product/productItemUtils"; +import { toast } from "sonner"; +import { getFeature } from "@/utils/product/entitlementUtils"; export const defaultProductItem: ProductItem = { feature_id: null, @@ -36,20 +44,109 @@ export const defaultProductItem: ProductItem = { reset_usage_when_enabled: true, }; -const defaultPriceItem: ProductItem = { - feature_id: null, - included_usage: null, +const useMergeFeatureItem = ({ + item, + setOpen, +}: { + item: ProductItem; + setOpen: (open: boolean) => void; +}) => { + const { product, setProduct } = useProductContext(); + const getOtherFeaturePriceItemIndex = () => { + return product.items.findIndex( + (i: any) => + i.feature_id === item.feature_id && + isFeaturePriceItem(i) && + itemsHaveSameInterval({ item1: i, item2: item }) + ); + }; - interval: ProductItemInterval.Month, + const shouldMergeFeatureItem = () => { + const otherItemIndex = getOtherFeaturePriceItemIndex(); + const isFeature = isFeatureItem(item); + return isFeature && otherItemIndex !== -1; + }; - // Price config - price: 0, - tiers: null, - billing_units: 1, + const mergeFeatureItem = () => { + const otherItemIndex = getOtherFeaturePriceItemIndex(); + const newItems = [...product.items]; + const newIncludedUsage = parseFloat(item.included_usage?.toString() || "0"); + if (isNaN(newIncludedUsage)) { + toast.error("You must set an included usage for this item"); + return; + } - // Others - entity_feature_id: null, - reset_usage_when_enabled: true, + newItems[otherItemIndex] = { + ...newItems[otherItemIndex], + included_usage: newIncludedUsage, + }; + + setProduct({ ...product, items: newItems }); + setOpen(false); + }; + + return { + shouldMergeFeatureItem, + mergeFeatureItem, + }; +}; + +const useMergeFeaturePriceItem = ({ + item, + setOpen, +}: { + item: ProductItem; + setOpen: (open: boolean) => void; +}) => { + const { product, setProduct, features } = useProductContext(); + + const getOtherFeatureItemIndex = () => { + return product.items.findIndex( + (i: any) => + i.feature_id === item.feature_id && + isFeatureItem(i) && + itemsHaveSameInterval({ item1: i, item2: item }) + ); + }; + + const shouldMergeFeaturePriceItem = () => { + const otherItemIndex = getOtherFeatureItemIndex(); + const isFeaturePrice = isFeaturePriceItem(item); + return isFeaturePrice && otherItemIndex !== -1 && item.feature_id; + }; + + const mergeFeaturePriceItem = () => { + const otherItemIndex = getOtherFeatureItemIndex(); + const otherItem = product.items[otherItemIndex]; + + // 1. If unlimited, don't allow this item + if (otherItem.included_usage === Infinite) { + toast.error( + `Cannot create a priced feature when you have another item for this feature (${otherItem.feature_id}) which is unlimited` + ); + return; + } + + const newItems = [...product.items]; + const newItem = validateProductItem({ + item: item as FrontendProductItem, + features, + }); + if (!newItem) return; + + newItems[otherItemIndex] = { + ...newItem, + included_usage: otherItem.included_usage, + }; + + setProduct({ ...product, items: newItems }); + setOpen(false); + }; + + return { + shouldMergeFeaturePriceItem, + mergeFeaturePriceItem, + }; }; export function CreateProductItem() { @@ -59,25 +156,52 @@ export function CreateProductItem() { const { features, product, setProduct, setFeatures, counts, mutate } = useProductContext(); - // const axiosInstance = useAxiosInstance(); - // const hasCustomers = counts?.all > 0; + const [configState, setConfigState] = useState({ + showPrice: false, + }); - // const setSelectedFeature = (feature: CreateFeatureType) => { - // setFeatures([...features, feature]); - // setItem({ ...item, feature_id: feature.id! }); - // }; + const { shouldMergeFeatureItem, mergeFeatureItem } = useMergeFeatureItem({ + item, + setOpen, + }); + const { shouldMergeFeaturePriceItem, mergeFeaturePriceItem } = + useMergeFeaturePriceItem({ + item, + setOpen, + }); + + const warning = () => { + if (shouldMergeFeatureItem() && item.feature_id) { + const feature = getFeature(item.feature_id, features); + return `You already have a usage-based price for ${feature?.name}. Adding this feature will merge it with that price, and create an overage price (eg 100 free, then $0.5 thereafter)`; + } + + if (shouldMergeFeaturePriceItem() && item.feature_id) { + const feature = getFeature(item.feature_id, features); + return `You already have a feature item for ${feature?.name}. Adding a variable price will merge it with that item, and create an overage price (eg 100 free, then $0.5 thereafter)`; + } + + return null; + }; const handleCreateProductItem = async (entityFeatureId?: string) => { + if (shouldMergeFeatureItem()) { + mergeFeatureItem(); + return; + } + + if (shouldMergeFeaturePriceItem()) { + mergeFeaturePriceItem(); + return; + } + const validatedItem = validateProductItem({ item: { - ...item, + ...(item as FrontendProductItem), entity_feature_id: entityFeatureId ? entityFeatureId : item.entity_feature_id, }, - // show: { - // price: true, - // }, features, }); @@ -93,12 +217,6 @@ export function CreateProductItem() { initialStep: CreateItemStep.CreateItem, }); - useEffect(() => { - if (open && isFeatureItem(item) && features.length == 0) { - stepState.replaceStep(CreateItemStep.CreateFeature); - } - }, [open]); - return ( @@ -127,7 +247,7 @@ export function CreateProductItem() { - */ -} -{ - /* - - -
- {showCreateFeature && ( - - )} - - - {showCreateFeature || - (features.length == 0 && item.price === null) - ? "Create Feature" - : "Add Product Item"} - -
-
-
- {showCreateFeature || - (features.length == 0 && item.price === null) ? ( -
- -
- ) : ( -
- -
- )} -
-
- {showCreateFeature || - (features.length == 0 && item.price === null) ? ( -
- ) : ( - {}} /> - )} - */ -} diff --git a/vite/src/views/products/product/product-item/EntitiesDropdown.tsx b/vite/src/views/products/product/product-item/EntitiesDropdown.tsx index 3b2824b9f..a50b5917a 100644 --- a/vite/src/views/products/product/product-item/EntitiesDropdown.tsx +++ b/vite/src/views/products/product/product-item/EntitiesDropdown.tsx @@ -113,20 +113,11 @@ export const EntitiesDropdownContent = () => { {}} - // setSelectedFeature={() => {}} setOpen={setCreateFeatureOpen} open={createFeatureOpen} entityCreate={true} /> - {/* - - Create Entity - - - */}
); diff --git a/vite/src/views/products/product/product-item/ProductItemConfig.tsx b/vite/src/views/products/product/product-item/ProductItemConfig.tsx index daa7c74a5..9d6142728 100644 --- a/vite/src/views/products/product/product-item/ProductItemConfig.tsx +++ b/vite/src/views/products/product/product-item/ProductItemConfig.tsx @@ -17,7 +17,12 @@ import { } from "@/utils/product/productItemUtils"; import { ConfigWithFeature } from "./components/ConfigWithFeature"; import FixedPriceConfig from "./components/ConfigFixedPrice"; -import { isFeaturePriceItem, isPriceItem } from "@/utils/product/getItemType"; +import { + isFeatureItem, + isFeaturePriceItem, + isPriceItem, +} from "@/utils/product/getItemType"; +import { PriceItemConfig } from "./product-item-config/PriceItemConfig"; export const ProductItemConfig = () => { // HOOKS @@ -75,33 +80,24 @@ export const ProductItemConfig = () => { newItem.config = newConfig; } } - // If showProration is false, don't touch the config at all - preserve whatever is there setItem(newItem); } } }, [item.feature_id, item.usage_model]); - const isPrice = isPriceItem(item); - + // const isFeature = isFeatureItem(item); + const isPrice = item.isPrice; + // isPriceItem(item) && "w-sm", + // isFeaturePriceItem(item) && "!w-sm", + // isFeaturePriceItem(item) && item.tiers?.length > 1 && "w-sm" return (
1 && "w-md" + "flex flex-col gap-6 w-sm transition-all ease-in-out duration-300 !overflow-visible" //modal animations )} > - {isPrice ? ( - - ) : ( - - )} + {isPrice ? : }
); }; diff --git a/vite/src/views/products/product/product-item/ProductItemRow.tsx b/vite/src/views/products/product/product-item/ProductItemRow.tsx index 54f377a9d..61f04b337 100644 --- a/vite/src/views/products/product/product-item/ProductItemRow.tsx +++ b/vite/src/views/products/product/product-item/ProductItemRow.tsx @@ -227,7 +227,6 @@ export const ProductItemRow = ({ }; const itemType = getItemType(item); - const isLast = index === product.items.length - 1; return (
{ const { product, features, org, entityFeatureIds, isOnboarding, autoSave } = @@ -31,7 +32,9 @@ export const ProductItemTable = () => { const [freeTrialOpen, setFreeTrialOpen] = useState(false); const handleRowClick = (item: ProductItem, index: number) => { - setSelectedItem(item); + const frontendItem = getFrontendItemConfig(item); + + setSelectedItem(frontendItem); setSelectedIndex(index); setOpen(true); }; diff --git a/vite/src/views/products/product/product-item/UpdateProductItem.tsx b/vite/src/views/products/product/product-item/UpdateProductItem.tsx index 8b6a2ebdb..470ad9eb2 100644 --- a/vite/src/views/products/product/product-item/UpdateProductItem.tsx +++ b/vite/src/views/products/product/product-item/UpdateProductItem.tsx @@ -1,7 +1,7 @@ import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"; import { useEffect, useState } from "react"; import { ProductItemConfig } from "./ProductItemConfig"; -import { ProductItem } from "@autumn/shared"; +import { FrontendProductItem, ProductItem } from "@autumn/shared"; import { ProductItemContext } from "./ProductItemContext"; import { useProductContext } from "../ProductContext"; import { notNullish } from "@/utils/genUtils"; @@ -14,6 +14,12 @@ import { CustomDialogFooter, } from "@/components/general/modal-components/DialogContentWrapper"; import { ItemConfigFooter } from "./product-item-config/item-config-footer/ItemConfigFooter"; +import { + AdvancedConfigSidebar, + MainDialogBodyWrapper, + ToggleAdvancedConfigButton, +} from "./product-item-config/AdvancedConfigSidebar"; +import { isPriceItem } from "@/utils/product/getItemType"; export default function UpdateProductItem({ selectedItem, @@ -31,9 +37,20 @@ export default function UpdateProductItem({ const { product, setProduct, features } = useProductContext(); const [showCreateFeature, setShowCreateFeature] = useState(false); + const [advancedOpen, setAdvancedOpen] = useState(false); + + useEffect(() => { + if (!open) { + setTimeout(() => { + setAdvancedOpen(false); + }, 300); + } + }, [open]); + const handleUpdateProductItem = () => { + const frontendItem = selectedItem as FrontendProductItem; const validatedItem = validateProductItem({ - item: selectedItem!, + item: frontendItem!, features, }); @@ -72,20 +89,31 @@ export default function UpdateProductItem({ }} > - - -
- Update Item - {selectedItem?.feature_id && ( - - {selectedItem.feature_id || ""} - - )} -
- -
- - + +
+ + +
+ Update Item + {selectedItem?.feature_id && ( + + {selectedItem.feature_id || ""} + + )} +
+ +
+ + +
+ +
{/* diff --git a/vite/src/views/products/product/product-item/components/ConfigWithFeature.tsx b/vite/src/views/products/product/product-item/components/ConfigWithFeature.tsx index 0a4ceac3b..27b93f608 100644 --- a/vite/src/views/products/product/product-item/components/ConfigWithFeature.tsx +++ b/vite/src/views/products/product/product-item/components/ConfigWithFeature.tsx @@ -5,30 +5,76 @@ import { useProductContext } from "../../ProductContext"; import { FeatureType } from "@autumn/shared"; import { getFeature } from "@/utils/product/entitlementUtils"; import { FeatureConfig } from "../product-item-config/FeatureItemConfig"; +import { WarningBox } from "@/components/general/modal-components/WarningBox"; +import { ArrowRight } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { isFeatureItem, isFeaturePriceItem } from "@/utils/product/getItemType"; +import { itemsHaveSameInterval } from "@/utils/product/productItemUtils"; +import { toast } from "sonner"; -export const ConfigWithFeature = ({ - show, - setShow, - handleAddPrice, -}: { - show: any; - setShow: (show: any) => void; - handleAddPrice: () => void; -}) => { - const { features } = useProductContext(); - const { item } = useProductItemContext(); +export const ConfigWithFeature = () => { + const { features, product, setProduct } = useProductContext(); + const { item, isUpdate, setOpen, warning } = useProductItemContext(); const isBooleanFeature = getFeature(item.feature_id, features)?.type === FeatureType.Boolean; + const otherItemIndex = product.items.findIndex( + (i: any) => + i.feature_id === item.feature_id && + isFeaturePriceItem(i) && + itemsHaveSameInterval({ item1: i, item2: item }) + ); + + const handleAddToExistingItem = () => { + const newItems = [...product.items]; + const newIncludedUsage = parseFloat(item.included_usage); + if (!item.included_usage || isNaN(newIncludedUsage)) { + toast.error("You must set an included usage for this item"); + return; + } + newItems[otherItemIndex] = { + ...newItems[otherItemIndex], + included_usage: newIncludedUsage, + }; + + setProduct({ ...product, items: newItems }); + setOpen(false); + }; + return (
Feature - +
{!isBooleanFeature && } + + {warning && ( + +
+
+ {/* You already have a usage-based price for this feature. If you're + looking to make it an overage (eg. 100 free, then $0.5 + thereafter), you should add it to the existing item. */} + {warning} +
+ + {/*
+ +
*/} +
+
+ )}
); }; diff --git a/vite/src/views/products/product/product-item/components/SelectItemFeature.tsx b/vite/src/views/products/product/product-item/components/SelectItemFeature.tsx index 2713cb19d..584731064 100644 --- a/vite/src/views/products/product/product-item/components/SelectItemFeature.tsx +++ b/vite/src/views/products/product/product-item/components/SelectItemFeature.tsx @@ -16,24 +16,12 @@ import { getItemType } from "@/utils/product/productItemUtils"; import { CreateItemStep } from "../utils/CreateItemStep"; import { useEffect, useState } from "react"; -export const SelectItemFeature = ({ - show, - setShow, -}: { - show: any; - setShow: any; -}) => { +export const SelectItemFeature = () => { const { features } = useProductContext(); const { item, setItem, isUpdate, stepState } = useProductItemContext(); const [open, setOpen] = useState(false); const itemType = getItemType(item); - // useEffect(() => { - // if (stepState.previousStep === CreateItemStep.SelectItemType) { - // setOpen(true); - // } - // }, [stepState.previousStep]); - return (
-// ); -// } +const MultiTierPrice = ({ + handleAddTier, + handleRemoveTier, + setUsageTier, +}: { + handleAddTier: () => void; + handleRemoveTier: (index: number) => void; + setUsageTier: (index: number, key: string, value: string | number) => void; +}) => { + const { item, setItem } = useProductItemContext(); + return ( + <> + {item.tiers?.map((tier: any, index: number) => ( +
+
+
+
+ {/* {index == 0 && item.included_usage > 0 && ( + then + )} */} + null} + type="from" + /> +
+ to +
+ { + setUsageTier(index, "to", e.target.value); + }} + type="to" + /> +
+
-// return ( -//
-// -// {type === "amount" && ( -// -// USD -// -// )} -//
-// ); -// }; +
+ setUsageTier(index, "amount", e.target.value)} + type="amount" + /> +
+ 0} /> +
+
+ + +
+
+ ))} + + ); +}; + +const SingleTierPrice = ({ handleAddTier }: { handleAddTier: () => void }) => { + const { item, setItem } = useProductItemContext(); + const { org } = useOrg(); + const currency = org?.default_currency.toUpperCase() ?? "USD"; + + return ( +
+
+ + setItem({ + ...item, + tiers: [{ amount: e.target.value, to: Infinite }], + }) + } + endContent={ + {currency} + } + /> + +
+ +
+ ); +}; diff --git a/vite/src/views/products/product/product-item/product-item-config/components/feature-price/UsageTierInput.tsx b/vite/src/views/products/product/product-item/product-item-config/components/feature-price/UsageTierInput.tsx index 3d5129b24..129e1d78f 100644 --- a/vite/src/views/products/product/product-item/product-item-config/components/feature-price/UsageTierInput.tsx +++ b/vite/src/views/products/product/product-item/product-item-config/components/feature-price/UsageTierInput.tsx @@ -1,5 +1,6 @@ import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; +import { useProductContext } from "@/views/products/product/ProductContext"; import { Infinite } from "@autumn/shared"; export const UsageTierInput = ({ @@ -11,6 +12,10 @@ export const UsageTierInput = ({ onChange: (e: any) => void; type: "from" | "to" | "amount"; }) => { + const { org } = useProductContext(); + + const defaultCurrency = org?.currency?.toUpperCase() ?? "USD"; + if ((type === "to" && value === Infinite) || type === "from") { return ( {type === "amount" && ( - - USD + + {defaultCurrency} )}
diff --git a/vite/src/views/products/product/product-item/product-item-config/item-config-footer/ItemConfigFooter.tsx b/vite/src/views/products/product/product-item/product-item-config/item-config-footer/ItemConfigFooter.tsx index 02ce3f3db..0b81f712b 100644 --- a/vite/src/views/products/product/product-item/product-item-config/item-config-footer/ItemConfigFooter.tsx +++ b/vite/src/views/products/product/product-item/product-item-config/item-config-footer/ItemConfigFooter.tsx @@ -33,7 +33,7 @@ export const ItemConfigFooter = ({ const showIntro = product.items.length === 0; return ( - + {handleBack ? (
)} -
+
{handleUpdateProductItem && (