diff --git a/.env.example b/.env.example index fd26d65..2e55d6e 100644 --- a/.env.example +++ b/.env.example @@ -60,3 +60,11 @@ GOOGLE_SHEETS_CLIENT_SECRET="" GOOGLE_DRIVE_CLIENT_ID="" GOOGLE_DRIVE_CLIENT_SECRET="" +# DigitalOcean Spaces (S3-compatible Object Storage) +DO_SPACES_KEY="" +DO_SPACES_SECRET="" +DO_SPACES_ENDPOINT="https://blr1.digitaloceanspaces.com" +DO_SPACES_BUCKET="nodebase-media" +DO_SPACES_REGION="blr1" +DO_SPACES_CDN_URL="" +DO_SPACES_SAS_EXPIRY_HOURS="48" diff --git a/.github/workflows/deploy-digitalocean.yml b/.github/workflows/deploy-digitalocean.yml new file mode 100644 index 0000000..ea3456d --- /dev/null +++ b/.github/workflows/deploy-digitalocean.yml @@ -0,0 +1,135 @@ +name: Build and Deploy to DigitalOcean + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + REGISTRY: registry.digitalocean.com/nodebase + IMAGE_NAME: nodebase + +jobs: + # ─── Build & Push Docker image to DigitalOcean Container Registry ─── + build-and-push: + name: Build & Push to DOCR + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + permissions: + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Log in to DigitalOcean Container Registry + run: doctl registry login --expiry-seconds 1200 + + - name: Build Docker image + run: | + docker build \ + -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }} \ + -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ + . + + - name: Push Docker image + run: | + docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }} + docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + # ─── Deploy to DigitalOcean App Platform ──────────────────────────── + deploy: + name: Deploy to App Platform + runs-on: ubuntu-latest + needs: build-and-push + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + + steps: + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Deploy to App Platform + env: + APP_ID: ${{ secrets.APP_ID }} + APP_NAME: nodebase + run: | + if [ -z "$APP_ID" ]; then + for candidate_id in $(doctl apps list --format ID --no-header); do + candidate_name=$(doctl apps get "$candidate_id" --format Spec.Name --no-header) + if [ "$candidate_name" = "$APP_NAME" ]; then + APP_ID="$candidate_id" + break + fi + done + fi + if [ -z "$APP_ID" ]; then + echo "❌ No App Platform app found. Create one first in DigitalOcean console." + exit 1 + fi + echo "🚀 Triggering deployment for App: $APP_ID" + doctl apps create-deployment "$APP_ID" --wait + echo "✅ Deployment complete!" + + # ─── PR Build Validation ──────────────────────────────────────────── + build-check: + name: Validate build (PR only) + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + permissions: + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Generate Prisma client + run: npx prisma generate + + - name: Type check + run: npx tsc --noEmit + + - name: Build + run: npm run build + env: + NODE_OPTIONS: "--max-old-space-size=4096" + DATABASE_URL: "postgresql://dummy:dummy@dummy:5432/dummy" + DIRECT_DATABASE_URL: "postgresql://dummy:dummy@dummy:5432/dummy" + BETTER_AUTH_SECRET: "dummy-secret-for-build-only" + BETTER_AUTH_URL: "https://nodebase.tech" + NEXT_PUBLIC_BETTER_AUTH_URL: "https://nodebase.tech" + NEXT_PUBLIC_APP_URL: "https://nodebase.tech" + INNGEST_SIGNING_KEY: "signkey-prod-dummy" + INNGEST_EVENT_KEY: "dummy-event-key" + ENCRYPTION_KEY: "dummy-encryption-key-32-characters" + GOOGLE_CLIENT_ID: "dummy" + GOOGLE_CLIENT_SECRET: "dummy" + GOOGLE_GMAIL_CLIENT_ID: "dummy" + GOOGLE_GMAIL_CLIENT_SECRET: "dummy" + GOOGLE_SHEETS_CLIENT_ID: "dummy" + GOOGLE_SHEETS_CLIENT_SECRET: "dummy" + GOOGLE_DRIVE_CLIENT_ID: "dummy" + GOOGLE_DRIVE_CLIENT_SECRET: "dummy" + GITHUB_CLIENT_ID: "dummy" + GITHUB_CLIENT_SECRET: "dummy" + GROQ_API_KEY: "dummy" + GOOGLE_GENERATIVE_AI_API_KEY: "dummy" + POLAR_ACCESS_TOKEN: "dummy" + POLAR_WEBHOOK_SECRET: "dummy" + SENTRY_AUTH_TOKEN: "dummy" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 0f77570..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,108 +0,0 @@ -name: Build and Deploy to Azure Container Apps - -on: - push: - branches: [main] - pull_request: - branches: [main] - -env: - REGISTRY: nodebaseacr.azurecr.io - IMAGE_NAME: nodebase - RESOURCE_GROUP: nodebase-prod-rg - CONTAINER_APP: nodebase-app - CONTAINER_APP_ENV: nodebase-env - -jobs: - build-and-push: - name: Build Docker image and push to ACR - runs-on: ubuntu-latest - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - permissions: - contents: read - - outputs: - image-tag: ${{ steps.meta.outputs.version }} - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Log in to Azure Container Registry - uses: docker/login-action@v3 - with: - registry: nodebaseacr.azurecr.io - username: ${{ secrets.ACR_USERNAME }} - password: ${{ secrets.ACR_PASSWORD }} - - - name: Extract metadata for Docker - id: meta - uses: docker/metadata-action@v5 - with: - images: nodebaseacr.azurecr.io/nodebase - tags: | - type=sha,prefix=sha-,format=long - type=raw,value=latest - - - name: Build and push Docker image - uses: docker/build-push-action@v5 - with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=nodebaseacr.azurecr.io/nodebase:latest - cache-to: type=inline - - deploy: - name: Deployment complete - runs-on: ubuntu-latest - needs: build-and-push - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - steps: - - name: Done - run: | - echo "✅ Image pushed to Azure Container Registry successfully." - echo "📦 Image: nodebaseacr.azurecr.io/nodebase:sha-${{ github.sha }}" - echo "🚀 Azure Container App will auto-redeploy via ACR webhook." - echo "🌐 Your app will be live in ~2 minutes at your Azure URL." - - build-check: - name: Validate build (PR only) - runs-on: ubuntu-latest - if: github.event_name == 'pull_request' - permissions: - contents: read - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Generate Prisma client - run: npx prisma generate - - - name: Type check - run: npx tsc --noEmit - - - name: Build - run: npm run build - env: - NODE_OPTIONS: "--max-old-space-size=4096" - DATABASE_URL: "postgresql://dummy:dummy@dummy:5432/dummy" - DIRECT_DATABASE_URL: "postgresql://dummy:dummy@dummy:5432/dummy" - BETTER_AUTH_SECRET: "dummy-secret-for-build-only" - BETTER_AUTH_URL: "https://dummy.azurecontainerapps.io" - NEXT_PUBLIC_BETTER_AUTH_URL: "https://dummy.azurecontainerapps.io" - NEXT_PUBLIC_APP_URL: "https://dummy.azurecontainerapps.io" - INNGEST_SIGNING_KEY: "signkey-prod-dummy" - INNGEST_EVENT_KEY: "dummy-event-key" - ENCRYPTION_KEY: "dummy-encryption-key-32-characters" \ No newline at end of file diff --git a/.github/workflows/nodebase-app-AutoDeployTrigger-5e61cb78-dd30-4542-9ea3-615a7ad15fd2.yml b/.github/workflows/nodebase-app-AutoDeployTrigger-5e61cb78-dd30-4542-9ea3-615a7ad15fd2.yml deleted file mode 100644 index 61202f6..0000000 --- a/.github/workflows/nodebase-app-AutoDeployTrigger-5e61cb78-dd30-4542-9ea3-615a7ad15fd2.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Trigger auto deployment for nodebase-app - -# When this action will be executed -on: - # Automatically trigger it when detected changes in repo - push: - branches: - [ main ] - paths: - - '**' - - '.github/workflows/nodebase-app-AutoDeployTrigger-5e61cb78-dd30-4542-9ea3-615a7ad15fd2.yml' - - # Allow manual trigger - workflow_dispatch: - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - permissions: - id-token: write #This is required for requesting the OIDC JWT Token - contents: read #Required when GH token is used to authenticate with private repo - - steps: - - name: Checkout to the branch - uses: actions/checkout@v2 - - - name: Azure Login - uses: azure/login@v2 - with: - client-id: ${{ secrets.NODEBASEAPP_AZURE_CLIENT_ID }} - tenant-id: ${{ secrets.NODEBASEAPP_AZURE_TENANT_ID }} - subscription-id: ${{ secrets.NODEBASEAPP_AZURE_SUBSCRIPTION_ID }} - - - name: Build and push container image to registry - uses: azure/container-apps-deploy-action@v2 - with: - appSourcePath: ${{ github.workspace }}"./Dockerfile" - _dockerfilePathKey_: _dockerfilePath_ - _targetLabelKey_: _targetLabel_ - registryUrl: nodebaseacr.azurecr.io - registryUsername: ${{ secrets.NODEBASEAPP_REGISTRY_USERNAME }} - registryPassword: ${{ secrets.NODEBASEAPP_REGISTRY_PASSWORD }} - containerAppName: nodebase-app - resourceGroup: nodebase-prod-rg - imageToBuild: nodebaseacr.azurecr.io/nodebase-app:${{ github.sha }} - _buildArgumentsKey_: | - _buildArgumentsValues_ - - diff --git a/Dockerfile b/Dockerfile index 8e13ad1..b26ff09 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ COPY . . RUN npx prisma generate # Dummy env vars so Next.js can build without real credentials -# Real values are injected at runtime by Azure Container Apps +# Real values are injected at runtime by DigitalOcean App Platform ENV NEXT_TELEMETRY_DISABLED=1 ENV DATABASE_URL="postgresql://dummy:dummy@dummy:5432/dummy" ENV DIRECT_DATABASE_URL="postgresql://dummy:dummy@dummy:5432/dummy" diff --git a/next-sitemap.config.js b/next-sitemap.config.js new file mode 100644 index 0000000..c1c543f --- /dev/null +++ b/next-sitemap.config.js @@ -0,0 +1,40 @@ +/** @type {import('next-sitemap').IConfig} */ +module.exports = { + siteUrl: "https://nodebase.tech", + generateRobotsTxt: true, + generateIndexSitemap: false, + changefreq: "weekly", + priority: 0.7, + sitemapSize: 5000, + exclude: [ + "/workflows/*", + "/editor/*", + "/settings/*", + "/api/*", + "/verify-email", + "/check-email", + "/resend-verification", + ], + additionalPaths: async (config) => [ + await config.transform(config, "/"), + await config.transform(config, "/pricing"), + await config.transform(config, "/blog"), + await config.transform(config, "/integrations"), + await config.transform(config, "/login"), + await config.transform(config, "/signup"), + ], + robotsTxtOptions: { + policies: [ + { + userAgent: "*", + allow: "/", + disallow: ["/workflows/", "/editor/", "/settings/", "/api/"], + }, + { + userAgent: "Googlebot", + allow: "/", + disallow: ["/workflows/", "/editor/", "/settings/"], + }, + ], + }, +} diff --git a/next.config.ts b/next.config.ts index d5b5b33..c9c354c 100644 --- a/next.config.ts +++ b/next.config.ts @@ -4,6 +4,15 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { output: "standalone", devIndicators: false, + // AWS SDK v3 uses deep subpath exports that Turbopack can't resolve — + // mark them as external so Node.js handles module resolution natively + serverExternalPackages: [ + "@aws-sdk/client-s3", + "@aws-sdk/s3-request-presigner", + "@aws-sdk/core", + "@aws-sdk/signature-v4-multi-region", + "@smithy/core", + ], async redirects() { return []; diff --git a/package-lock.json b/package-lock.json index db75485..db21181 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,13 +15,12 @@ "@ai-sdk/openai": "^3.0.14", "@ai-sdk/perplexity": "^3.0.8", "@ai-sdk/xai": "^3.0.26", - "@azure/storage-blob": "^12.31.0", + "@aws-sdk/client-s3": "^3.1060.0", + "@aws-sdk/s3-request-presigner": "^3.1060.0", "@hookform/resolvers": "^5.2.2", "@inngest/realtime": "^0.4.5", "@monaco-editor/react": "^4.7.0", "@paralleldrive/cuid2": "^3.0.4", - "@polar-sh/better-auth": "^1.8.2", - "@polar-sh/sdk": "^0.46.3", "@prisma/client": "^6.17.1", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-alert-dialog": "^1.1.15", @@ -59,6 +58,7 @@ "@vercel/analytics": "^1.6.1", "@xyflow/react": "^12.9.2", "ai": "^6.0.45", + "bcryptjs": "^3.0.3", "better-auth": "^1.2.7", "class-variance-authority": "^0.7.1", "client-only": "^0.0.1", @@ -77,6 +77,7 @@ "lucide-react": "^0.546.0", "motion": "^12.29.0", "next": "^15.5.13", + "next-sitemap": "^4.2.3", "next-themes": "^0.4.6", "node-fetch": "^2.7.0", "nodemailer": "^7.0.11", @@ -84,6 +85,7 @@ "pg": "^8.20.0", "pg-cursor": "^2.12.1", "random-word-slugs": "^0.1.7", + "razorpay": "^2.9.6", "react": "19.1.0", "react-day-picker": "^9.11.1", "react-dom": "19.1.0", @@ -91,6 +93,7 @@ "react-hook-form": "^7.65.0", "react-resizable-panels": "^3.0.6", "recharts": "^2.15.4", + "schema-dts": "^2.0.0", "server-only": "^0.0.1", "sonner": "^2.0.7", "stripe": "^20.4.1", @@ -105,6 +108,7 @@ "devDependencies": { "@biomejs/biome": "2.2.0", "@tailwindcss/postcss": "^4", + "@types/bcryptjs": "^2.4.6", "@types/node": "^20", "@types/node-fetch": "^2.6.13", "@types/nodemailer": "^7.0.11", @@ -514,208 +518,517 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@azure/abort-controller": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", - "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", - "license": "MIT", + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@azure/core-auth": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", - "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", - "license": "MIT", + "node_modules/@aws-crypto/crc32c": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", + "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", + "license": "Apache-2.0", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-util": "^1.13.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", + "integrity": "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.1060.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1060.0.tgz", + "integrity": "sha512-lYdSUOE965Cz/kb3YVDMKz7C4icH0yJxkwB5M0KKAu1nGWT3L78Ty5g2wP3AhZEKH5VzNhPUo8AEcspWOfAGCw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/credential-provider-node": "^3.972.50", + "@aws-sdk/middleware-bucket-endpoint": "^3.972.19", + "@aws-sdk/middleware-expect-continue": "^3.972.15", + "@aws-sdk/middleware-flexible-checksums": "^3.974.25", + "@aws-sdk/middleware-location-constraint": "^3.972.12", + "@aws-sdk/middleware-sdk-s3": "^3.972.46", + "@aws-sdk/middleware-ssec": "^3.972.12", + "@aws-sdk/signature-v4-multi-region": "^3.996.31", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/fetch-http-handler": "^5.4.6", + "@smithy/node-http-handler": "^4.7.6", + "@smithy/types": "^4.14.3", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@azure/core-client": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz", - "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==", - "license": "MIT", + "node_modules/@aws-sdk/core": { + "version": "3.974.17", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.17.tgz", + "integrity": "sha512-r8o4h2K7j6P9ngno+8ei0aK0U/4JwDb7A2fMMxGVoSqDN8AFlIzSDeZHME9LcVLR2codyhtr1WAAg+/nmkeeMA==", + "license": "Apache-2.0", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-auth": "^1.10.0", - "@azure/core-rest-pipeline": "^1.22.0", - "@azure/core-tracing": "^1.3.0", - "@azure/core-util": "^1.13.0", - "@azure/logger": "^1.3.0", + "@aws-sdk/types": "^3.973.10", + "@aws-sdk/xml-builder": "^3.972.27", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/core": "^3.24.6", + "@smithy/signature-v4": "^5.4.6", + "@smithy/types": "^4.14.3", + "bowser": "^2.11.0", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@azure/core-http-compat": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.2.tgz", - "integrity": "sha512-Tf6ltdKzOJEgxZeWLCjMxrxbodB/ZeCbzzA1A2qHbhzAjzjHoBVSUeSl/baT/oHAxhc4qdqVaDKnc2+iE932gw==", - "license": "MIT", + "node_modules/@aws-sdk/crc64-nvme": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.10.tgz", + "integrity": "sha512-QsyJJlx+bSgApcd6kkloZ+nHg2nWJTwUA39/KiDcNRYjz9UOReQcNJRlJBImK+eF9EWl2LG5SW7LaVFuYUE8HQ==", + "license": "Apache-2.0", "dependencies": { - "@azure/abort-controller": "^2.1.2" + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.43.tgz", + "integrity": "sha512-g0XVQKzaA/4cq1vz1IvCQwYM+1Pkv01J9yHDpCTXekVuGZRDEz0wqBQ1AuYTq7FM6uik4uBGH8Tb5d9YvgeA7g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@azure/core-client": "^1.10.0", - "@azure/core-rest-pipeline": "^1.22.0" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@azure/core-lro": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", - "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.45", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.45.tgz", + "integrity": "sha512-w9PuOoKCt6+xoESvY+zlV0u3PKQ0mVL259PcsVR6a3S/uYJJHnIi4r1NxdJHEcNldUVRIciltWnFMGBR4YEm3g==", + "license": "Apache-2.0", "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-util": "^1.2.0", - "@azure/logger": "^1.0.0", + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/fetch-http-handler": "^5.4.6", + "@smithy/node-http-handler": "^4.7.6", + "@smithy/types": "^4.14.3", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@azure/core-paging": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz", - "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.972.48", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.48.tgz", + "integrity": "sha512-+6BQ6Lrnc+EyAGElLRW6j+Sa+RirPHnIJsobvYO6nnyK+oGKmz1ne/ieclbLWyjyDKEU3/JVJWcWY3VLFPvGtQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/credential-provider-env": "^3.972.43", + "@aws-sdk/credential-provider-http": "^3.972.45", + "@aws-sdk/credential-provider-login": "^3.972.47", + "@aws-sdk/credential-provider-process": "^3.972.43", + "@aws-sdk/credential-provider-sso": "^3.972.47", + "@aws-sdk/credential-provider-web-identity": "^3.972.47", + "@aws-sdk/nested-clients": "^3.997.15", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/credential-provider-imds": "^4.3.7", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.47", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.47.tgz", + "integrity": "sha512-Iy2ebWVgrZBH05464uJiQYu6HSSiROnwVZptthEFXx2gWjo1ORCxEAFZB5Cr2MdfrSnZ+0QUPkZ1ZpCqpkUrLQ==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/nested-clients": "^3.997.15", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@azure/core-rest-pipeline": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.23.0.tgz", - "integrity": "sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.50", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.50.tgz", + "integrity": "sha512-b05Aelq5cqAvCCDQjCYacl0XmR8QhBNSqLbsdISkQmlQBa5oPS66zYPteWcSp5LswbpoIe552EUGjluKiadBig==", + "license": "Apache-2.0", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-auth": "^1.10.0", - "@azure/core-tracing": "^1.3.0", - "@azure/core-util": "^1.13.0", - "@azure/logger": "^1.3.0", - "@typespec/ts-http-runtime": "^0.3.4", + "@aws-sdk/credential-provider-env": "^3.972.43", + "@aws-sdk/credential-provider-http": "^3.972.45", + "@aws-sdk/credential-provider-ini": "^3.972.48", + "@aws-sdk/credential-provider-process": "^3.972.43", + "@aws-sdk/credential-provider-sso": "^3.972.47", + "@aws-sdk/credential-provider-web-identity": "^3.972.47", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/credential-provider-imds": "^4.3.7", + "@smithy/types": "^4.14.3", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@azure/core-tracing": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz", - "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.43.tgz", + "integrity": "sha512-GPokLNyvTfCmuaHk+v3GKVs4ZT3cMu5kgS2a+NPkOMt96cq6fSIK0g+mZHpGS6Cd4QGrPKesANEaLUKgOskTzg==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@azure/core-util": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", - "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.972.47", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.47.tgz", + "integrity": "sha512-0AzvLrzlvJs0DzbeWGvNj+bX3Uzd7VNS6vDqCOdZzBlCGKGd78uxctJSW9iK/Rt/nxiJqpTvrYQlVJ4guVM2Dw==", + "license": "Apache-2.0", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@typespec/ts-http-runtime": "^0.3.0", + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/nested-clients": "^3.997.15", + "@aws-sdk/token-providers": "3.1060.0", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@azure/core-xml": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.5.0.tgz", - "integrity": "sha512-D/sdlJBMJfx7gqoj66PKVmhDDaU6TKA49ptcolxdas29X7AfvLTmfAGLjAcIMBK7UZ2o4lygHIqVckOlQU3xWw==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.47", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.47.tgz", + "integrity": "sha512-eksfbUErOejUAGWBAcNqaP7IX21oUOEo73d9R56k9Ua4d57qS90NEYkWJsuSGzTXMFulCu17qXJI/qGmM7hvoA==", + "license": "Apache-2.0", "dependencies": { - "fast-xml-parser": "^5.0.7", - "tslib": "^2.8.1" + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/nested-clients": "^3.997.15", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@azure/logger": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", - "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.972.19", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.19.tgz", + "integrity": "sha512-BkjsoevWdtXyfmItfvNW693XO/T2ooXAz3wx3fX1Y7YUHJB+Pvj7XM6Mu9n6lCQ32tF88NzguCOlL8G7e62SOA==", + "license": "Apache-2.0", "dependencies": { - "@typespec/ts-http-runtime": "^0.3.0", + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@azure/storage-blob": { - "version": "12.31.0", - "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.31.0.tgz", - "integrity": "sha512-DBgNv10aCSxopt92DkTDD0o9xScXeBqPKGmR50FPZQaEcH4JLQ+GEOGEDv19V5BMkB7kxr+m4h6il/cCDPvmHg==", - "license": "MIT", - "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-auth": "^1.9.0", - "@azure/core-client": "^1.9.3", - "@azure/core-http-compat": "^2.2.0", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.6.2", - "@azure/core-rest-pipeline": "^1.19.1", - "@azure/core-tracing": "^1.2.0", - "@azure/core-util": "^1.11.0", - "@azure/core-xml": "^1.4.5", - "@azure/logger": "^1.1.4", - "@azure/storage-common": "^12.3.0", - "events": "^3.0.0", - "tslib": "^2.8.1" + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.972.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.15.tgz", + "integrity": "sha512-GFxHAXAO2iV4EIYZ97NcIiJiMATEjCm9sWS0VaRvHgxE9EDsL2tF0J08si74IT/YqFsdOgF/GWtoI2LkgbGj/Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@azure/storage-common": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/@azure/storage-common/-/storage-common-12.3.0.tgz", - "integrity": "sha512-/OFHhy86aG5Pe8dP5tsp+BuJ25JOAl9yaMU3WZbkeoiFMHFtJ7tu5ili7qEdBXNW9G5lDB19trwyI6V49F/8iQ==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.974.25", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.25.tgz", + "integrity": "sha512-u4EmdygVkPTO0UjNcXqqXR5eG5WWzU2bGan1ZsujTqgC1PLDtgXqqK8LbySJ7i1gefAggHfUztZ5B67NLhmKJQ==", + "license": "Apache-2.0", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-auth": "^1.9.0", - "@azure/core-http-compat": "^2.2.0", - "@azure/core-rest-pipeline": "^1.19.1", - "@azure/core-tracing": "^1.2.0", - "@azure/core-util": "^1.11.0", - "@azure/logger": "^1.1.4", - "events": "^3.3.0", - "tslib": "^2.8.1" + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/crc64-nvme": "^3.972.10", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.972.12", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.12.tgz", + "integrity": "sha512-9fXwH5lPa4M9lD6KhKOWZX2sXefuJX0PR/vxZ2u/ZYVrgr/tEUiFTdEBJ88y3/psuocWQ5IZmf5+T1hsa1qDUA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.10", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.972.46", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.46.tgz", + "integrity": "sha512-ziGg3WIaAyRb8SO5fdoHBg+u6ikOhDN8QOagRKvZtDkfxFizHdDufCSoQkaOfvlpIxXRvTlFUaHpylMih4/KCw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/signature-v4-multi-region": "^3.996.31", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.972.12", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.12.tgz", + "integrity": "sha512-WiuUb6fqkMAAM3b1+2M2B74Zobh4JUsoS0s2gE792IRJCYaGp2BJzMK9rhfniNijxg1PhVppUeufpiEdDLNy+w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.10", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.15.tgz", + "integrity": "sha512-Fpri1/PXKMKveORZ7E00VLTlWS5DkfZkW70PUE+bOnpWpAeHAQLoiDHhkzN3kNWbbSsGg64+IZYiq/EZgME3Mg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/signature-v4-multi-region": "^3.996.31", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/fetch-http-handler": "^5.4.6", + "@smithy/node-http-handler": "^4.7.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner": { + "version": "3.1060.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.1060.0.tgz", + "integrity": "sha512-20lX+iQNrEinYavfSgZuo9YlLn4U+o0xFl4Fw4oMZ2T2UHEh0dGDcDQkbpydtnzUAlzCQE0WRnDKO65daFC4Sg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/signature-v4-multi-region": "^3.996.31", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.31", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.31.tgz", + "integrity": "sha512-Kn2up9SlG1KC6wRtwf0d7waTGF6rvp9DxYqB54x6UCKdQ6kyaXCqHL4WGb5vUJga5kS8FxnjhY0LqM28aMvnNQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.10", + "@smithy/signature-v4": "^5.4.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1060.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1060.0.tgz", + "integrity": "sha512-6NZaMKkFhpaNiwLpHi1sZaYjidL/lCJE6ME6NxwA8gv9vQna+Kr0j4OFwVoz6tANRWM3WbGz6jiPsGX/Vkjwow==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.17", + "@aws-sdk/nested-clients": "^3.997.15", + "@aws-sdk/types": "^3.973.10", + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.973.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.10.tgz", + "integrity": "sha512-992QrTO7G9qCvKD0fx1rMlqcL14plUcRAbwmqqYVsuF3GrqcvlAL9qxR+baMafarEZ+l7DUQ5lCMmt5mbMhF7g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", + "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.27", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.27.tgz", + "integrity": "sha512-hpsCXCOI436kxWpjtRuIHVvuPP81MOw8f18jzfZeg+UOiiOvlqWcmWChzEhJEu16cOC6+ku4ncBN+7rdt+DZ9g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.3", + "fast-xml-parser": "5.7.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", + "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -1230,6 +1543,12 @@ "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", "license": "(Apache-2.0 AND BSD-3-Clause)" }, + "node_modules/@corex/deepmerge": { + "version": "4.0.43", + "resolved": "https://registry.npmjs.org/@corex/deepmerge/-/deepmerge-4.0.43.tgz", + "integrity": "sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==", + "license": "MIT" + }, "node_modules/@date-fns/tz": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", @@ -2686,6 +3005,53 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@nodable/entities": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.1.tgz", + "integrity": "sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@opentelemetry/api": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", @@ -4065,271 +4431,45 @@ "dependencies": { "@opentelemetry/core": "^2.0.0" }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0" - } - }, - "node_modules/@oxc-project/runtime": { - "version": "0.115.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.115.0.tgz", - "integrity": "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.115.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", - "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", - "devOptional": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@paralleldrive/cuid2": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-3.3.0.tgz", - "integrity": "sha512-OqiFvSOF0dBSesELYY2CAMa4YINvlLpvKOz/rv6NeZEqiyttlHgv98Juwv4Ch+GrEV7IZ8jfI2VcEoYUjXXCjw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "^2.0.1", - "bignumber.js": "^9.3.1", - "error-causes": "^3.0.2" - }, - "bin": { - "cuid2": "bin/cuid2.js" - } - }, - "node_modules/@polar-sh/better-auth": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@polar-sh/better-auth/-/better-auth-1.8.3.tgz", - "integrity": "sha512-9lASF4si+iU3pi3yNVhb+uZdqF7ZvF7J7GSq0w6YaZsr/oVXxd4l+v8cmJiq3crsEaXiJIBni6v3xHpzgCjtmQ==", - "dependencies": { - "@polar-sh/checkout": "^0.2.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "@polar-sh/sdk": "^0.46.4", - "better-auth": "^1.4.12", - "zod": "^3.24.2 || ^4" - } - }, - "node_modules/@polar-sh/checkout": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@polar-sh/checkout/-/checkout-0.2.0.tgz", - "integrity": "sha512-lkHa7JJtQpbHblsfpEX91bJRV6s7gyBIlehVCy2KRL89vP4t6t2vYKNwIxIHI+EG7RxXKu/4fCMchQYrVSMYuQ==", - "license": "Apache-2.0", - "dependencies": { - "@polar-sh/sdk": "^0.42.1", - "@polar-sh/ui": "^0.1.2", - "event-source-plus": "^0.1.15", - "eventemitter3": "^5.0.1", - "markdown-to-jsx": "^8.0.0", - "react-hook-form": "~7.70.0" - }, - "peerDependencies": { - "@stripe/react-stripe-js": "^3.6.0 || ^4.0.2", - "@stripe/stripe-js": "^7.1.0", - "react": "^18 || ^19" - } - }, - "node_modules/@polar-sh/checkout/node_modules/@polar-sh/sdk": { - "version": "0.42.5", - "resolved": "https://registry.npmjs.org/@polar-sh/sdk/-/sdk-0.42.5.tgz", - "integrity": "sha512-GzC3/ElCtMO55+KeXwFTANlydZzw5qI3DU/F9vAFIsUKuegSmh+Xu03KCL+ct9/imJOvLUQucYhUSsNKqo2j2Q==", - "dependencies": { - "standardwebhooks": "^1.0.0", - "zod": "^3.25.65 || ^4.0.0" - } - }, - "node_modules/@polar-sh/checkout/node_modules/@polar-sh/ui": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@polar-sh/ui/-/ui-0.1.2.tgz", - "integrity": "sha512-YTmMB2lr+PplMTDZnTs0Crgu0KNBKyQcSX4N0FYXSlo1Q6e9IKs4hwzEcqNUv3eHS4BxGO1SvxxNjuSK+il49Q==", - "license": "Apache-2.0", - "dependencies": { - "@radix-ui/react-accordion": "^1.2.12", - "@radix-ui/react-alert-dialog": "^1.1.15", - "@radix-ui/react-checkbox": "^1.3.3", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-label": "^2.1.7", - "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-radio-group": "^1.3.8", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.7", - "@radix-ui/react-slot": "^1.2.3", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-toast": "^1.2.15", - "@radix-ui/react-toggle": "^1.1.10", - "@radix-ui/react-toggle-group": "^1.1.11", - "@radix-ui/react-tooltip": "^1.2.8", - "@tanstack/react-table": "^8.21.3", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "cmdk": "^1.1.1", - "countries-list": "^3.2.0", - "date-fns": "^4.1.0", - "input-otp": "^1.4.2", - "lucide-react": "^0.547.0", - "react-day-picker": "^9.11.1", - "react-hook-form": "^7.65.0", - "react-timeago": "^8.3.0", - "recharts": "^3.3.0", - "tailwind-merge": "^3.3.1" - }, - "peerDependencies": { - "react": "^18 || ^19", - "react-dom": "^18 || ^19" - } - }, - "node_modules/@polar-sh/checkout/node_modules/@polar-sh/ui/node_modules/@radix-ui/react-toast": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", - "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", - "license": "MIT", - "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-dismissable-layer": "1.1.11", - "@radix-ui/react-portal": "1.1.9", - "@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-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@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" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@polar-sh/checkout/node_modules/@polar-sh/ui/node_modules/@tanstack/react-table": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", - "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", - "license": "MIT", - "dependencies": { - "@tanstack/table-core": "8.21.3" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/@polar-sh/checkout/node_modules/@polar-sh/ui/node_modules/recharts": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.8.0.tgz", - "integrity": "sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ==", - "license": "MIT", - "workspaces": [ - "www" - ], - "dependencies": { - "@reduxjs/toolkit": "^1.9.0 || 2.x.x", - "clsx": "^2.1.1", - "decimal.js-light": "^2.5.1", - "es-toolkit": "^1.39.3", - "eventemitter3": "^5.0.1", - "immer": "^10.1.1", - "react-redux": "8.x.x || 9.x.x", - "reselect": "5.1.1", - "tiny-invariant": "^1.3.3", - "use-sync-external-store": "^1.2.2", - "victory-vendor": "^37.0.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@polar-sh/checkout/node_modules/lucide-react": { - "version": "0.547.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.547.0.tgz", - "integrity": "sha512-YLChGBWKq8ynr1UWP8WWRPhHhyuBAXfSBnHSgfoj51L//9TU3d0zvxpigf5C1IJ4vnEoTzthl5awPK55PiZhdA==", - "license": "ISC", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "@opentelemetry/api": "^1.1.0" } }, - "node_modules/@polar-sh/checkout/node_modules/react-hook-form": { - "version": "7.70.0", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.70.0.tgz", - "integrity": "sha512-COOMajS4FI3Wuwrs3GPpi/Jeef/5W1DRR84Yl5/ShlT3dKVFUfoGiEZ/QE6Uw8P4T2/CLJdcTVYKvWBMQTEpvw==", + "node_modules/@oxc-project/runtime": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.115.0.tgz", + "integrity": "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-hook-form" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18 || ^19" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@polar-sh/checkout/node_modules/victory-vendor": { - "version": "37.3.6", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", - "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", - "license": "MIT AND ISC", - "dependencies": { - "@types/d3-array": "^3.0.3", - "@types/d3-ease": "^3.0.0", - "@types/d3-interpolate": "^3.0.1", - "@types/d3-scale": "^4.0.2", - "@types/d3-shape": "^3.1.0", - "@types/d3-time": "^3.0.0", - "@types/d3-timer": "^3.0.0", - "d3-array": "^3.1.6", - "d3-ease": "^3.0.1", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-shape": "^3.1.0", - "d3-time": "^3.0.0", - "d3-timer": "^3.0.1" + "node_modules/@oxc-project/types": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", + "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@polar-sh/sdk": { - "version": "0.46.4", - "resolved": "https://registry.npmjs.org/@polar-sh/sdk/-/sdk-0.46.4.tgz", - "integrity": "sha512-NnLTqx1M1GvN/fTsfg/MZRiH6TXnpzyiKGZISKaD4YLx80jmRuWUdUbbPtlq8I7cEuigGJAqTmqI167ldX4qPg==", + "node_modules/@paralleldrive/cuid2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-3.3.0.tgz", + "integrity": "sha512-OqiFvSOF0dBSesELYY2CAMa4YINvlLpvKOz/rv6NeZEqiyttlHgv98Juwv4Ch+GrEV7IZ8jfI2VcEoYUjXXCjw==", + "license": "MIT", "dependencies": { - "standardwebhooks": "^1.0.0", - "zod": "^3.25.65 || ^4.0.0" + "@noble/hashes": "^2.0.1", + "bignumber.js": "^9.3.1", + "error-causes": "^3.0.2" + }, + "bin": { + "cuid2": "bin/cuid2.js" } }, "node_modules/@prisma/client": { @@ -6158,42 +6298,6 @@ } } }, - "node_modules/@reduxjs/toolkit": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", - "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@standard-schema/utils": "^0.3.0", - "immer": "^11.0.0", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", - "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } - } - }, - "node_modules/@reduxjs/toolkit/node_modules/immer": { - "version": "11.1.4", - "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", - "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.0.0-rc.9", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", @@ -7322,11 +7426,125 @@ "webpack": ">=5.0.0" } }, - "node_modules/@stablelib/base64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", - "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", - "license": "MIT" + "node_modules/@smithy/core": { + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.6.tgz", + "integrity": "sha512-wBXDRup6UU97VKyaiRo8AssnfStPtG0oAAfpq/bC0a1YYau8pM86YB4kM6ccoVi1mS8l/UHbn9oDM+7uozr/ug==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.7.tgz", + "integrity": "sha512-xj8gq/bjFABAh6qWPSDCYcY3kzQIm4b561C+YnHH4zGq8rOgzQ3Shk+JGlpUxSd41UGiO6FkLdUCtNX1FAeHgg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.6.tgz", + "integrity": "sha512-FEwEYJ1jlBKdhe9TPzfghEi1bP55ZeEImlDkEa62bBBYzUcnB6RUCyuiS2mqKt6ZVjUbBgcNhzfIctH+Hevx9g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.6.tgz", + "integrity": "sha512-3fya8i7GrJilQouk4cZJKdy5k8MWQBpjfXrRNaXDedH8r779tr0jcxyH3+yoTmsluc2+vF4S343yFbnvu8ExDQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.6.tgz", + "integrity": "sha512-Ojg4B6oIDlIr1R86xCDJt1zJWnYa0VINmqdjfe9qxWjdRivHalZ3iSlQgVqYbW0MdpFOC5XfHEWsnbmdnpIILQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.6", + "@smithy/types": "^4.14.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.3.tgz", + "integrity": "sha512-YupL0ZWmFtJexUN2cHzkvvF/b9pKrtAIfT1o7/oY/Ppu8IYeZ+lDPM5vZdQJaSeA132dJCqojjGC9NhXeF71VQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } }, "node_modules/@standard-schema/spec": { "version": "1.1.0", @@ -7340,31 +7558,6 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, - "node_modules/@stripe/react-stripe-js": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-4.0.2.tgz", - "integrity": "sha512-l2wau+8/LOlHl+Sz8wQ1oDuLJvyw51nQCsu6/ljT6smqzTszcMHifjAJoXlnMfcou3+jK/kQyVe04u/ufyTXgg==", - "license": "MIT", - "peer": true, - "dependencies": { - "prop-types": "^15.7.2" - }, - "peerDependencies": { - "@stripe/stripe-js": ">=1.44.1 <8.0.0", - "react": ">=16.8.0 <20.0.0", - "react-dom": ">=16.8.0 <20.0.0" - } - }, - "node_modules/@stripe/stripe-js": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-7.9.0.tgz", - "integrity": "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12.16" - } - }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -7692,19 +7885,6 @@ "react": "^18 || ^19" } }, - "node_modules/@tanstack/table-core": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", - "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, "node_modules/@traceloop/ai-semantic-conventions": { "version": "0.20.0", "resolved": "https://registry.npmjs.org/@traceloop/ai-semantic-conventions/-/ai-semantic-conventions-0.20.0.tgz", @@ -7841,6 +8021,13 @@ "integrity": "sha512-rUYdp+MQwSFocxIOcSsYSF3YYYC/uUpMbCY/mbO21vGqfrEYvNSoPyKYDj6RhXXpPfS0KstW9RwG3qXh9sL7FQ==", "license": "MIT" }, + "node_modules/@types/bcryptjs": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", + "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/bunyan": { "version": "1.8.11", "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.11.tgz", @@ -8187,12 +8374,6 @@ "optional": true, "peer": true }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", - "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", - "license": "MIT" - }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", @@ -8217,42 +8398,6 @@ "@types/webidl-conversions": "*" } }, - "node_modules/@typespec/ts-http-runtime": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.4.tgz", - "integrity": "sha512-CI0NhTrz4EBaa0U+HaaUZrJhPoso8sG7ZFya8uQoBA57fjzrjRSv87ekCjLZOFExN+gXE/z0xuN2QfH4H2HrLQ==", - "license": "MIT", - "dependencies": { - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@typespec/ts-http-runtime/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/@typespec/ts-http-runtime/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/@upstash/redis": { "version": "1.37.0", "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.37.0.tgz", @@ -8865,9 +9010,28 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, "license": "MIT" }, + "node_modules/axios": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -8889,6 +9053,15 @@ "node": ">=6.0.0" } }, + "node_modules/bcryptjs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", + "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, "node_modules/better-auth": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.5.5.tgz", @@ -9039,6 +9212,12 @@ "node": "*" } }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", @@ -9051,6 +9230,18 @@ "node": "18 || 20 || >=22" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", @@ -9134,7 +9325,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -9344,7 +9534,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -9404,12 +9593,6 @@ "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/countries-list": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/countries-list/-/countries-list-3.3.0.tgz", - "integrity": "sha512-XRUjS+dcZuNh/fg3+mka3bXgcg4TbQZ1gaK5IJqO6qulerBANl1bmrd20P2dgmPkBpP+5FnejiSF1gd7bgAg+g==", - "license": "MIT" - }, "node_modules/cron-parser": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-5.5.0.tgz", @@ -9698,7 +9881,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -9717,6 +9899,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, "license": "MIT" }, "node_modules/detect-libc": { @@ -9771,7 +9954,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -9866,7 +10048,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9876,7 +10057,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9892,7 +10072,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -9905,7 +10084,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -9917,16 +10095,6 @@ "node": ">= 0.4" } }, - "node_modules/es-toolkit": { - "version": "1.45.1", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz", - "integrity": "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, "node_modules/esbuild": { "version": "0.27.4", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", @@ -10025,25 +10193,10 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, - "node_modules/event-source-plus": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/event-source-plus/-/event-source-plus-0.1.15.tgz", - "integrity": "sha512-kt3z/UwDbZxHttynwmXlqTf1qknWqPgswsbvSok1ob6SveMts4BqRXow6aiwB55xTY1XvSXuhn+IvYQErWLyKA==", - "license": "MIT", - "dependencies": { - "ofetch": "^1.5.1" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, "node_modules/events": { @@ -10051,6 +10204,7 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.8.x" } @@ -10126,11 +10280,21 @@ "node": ">=6.0.0" } }, - "node_modules/fast-sha256": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", - "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", - "license": "Unlicense" + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } }, "node_modules/fast-uri": { "version": "3.1.0", @@ -10150,9 +10314,9 @@ "peer": true }, "node_modules/fast-xml-builder": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", - "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "funding": [ { "type": "github", @@ -10161,13 +10325,14 @@ ], "license": "MIT", "dependencies": { - "path-expression-matcher": "^1.1.3" + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" } }, "node_modules/fast-xml-parser": { - "version": "5.5.6", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.6.tgz", - "integrity": "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", + "integrity": "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==", "funding": [ { "type": "github", @@ -10176,14 +10341,24 @@ ], "license": "MIT", "dependencies": { - "fast-xml-builder": "^1.1.4", - "path-expression-matcher": "^1.1.3", - "strnum": "^2.1.2" + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.7", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -10231,6 +10406,18 @@ "dev": true, "license": "MIT" }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -10247,11 +10434,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/form-data": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -10408,7 +10614,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -10442,7 +10647,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -10500,6 +10704,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -10520,7 +10736,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10569,7 +10784,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10582,7 +10796,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -10632,28 +10845,6 @@ ], "license": "MIT" }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-agent/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -10673,16 +10864,6 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "license": "MIT" }, - "node_modules/immer": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", - "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/import-in-the-middle": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-2.0.6.tgz", @@ -10826,6 +11007,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -10835,6 +11025,27 @@ "node": ">=8" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -11411,23 +11622,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/markdown-to-jsx": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-8.0.0.tgz", - "integrity": "sha512-hWEaRxeCDjes1CVUQqU+Ov0mCqBqkGhLKjL98KdbwHSgEWZZSJQeGlJQatVfeZ3RaxrfTrZZ3eczl2dhp5c/pA==", - "license": "MIT", - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "react": ">= 0.14.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, "node_modules/marked": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", @@ -11445,7 +11639,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -11465,6 +11658,15 @@ "license": "MIT", "peer": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/meshoptimizer": { "version": "0.22.0", "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.22.0.tgz", @@ -11472,6 +11674,31 @@ "dev": true, "license": "MIT" }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -11761,6 +11988,39 @@ } } }, + "node_modules/next-sitemap": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-4.2.3.tgz", + "integrity": "sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==", + "funding": [ + { + "url": "https://github.com/iamvishnusankar/next-sitemap.git" + } + ], + "license": "MIT", + "dependencies": { + "@corex/deepmerge": "^4.0.43", + "@next/env": "^13.4.3", + "fast-glob": "^3.2.12", + "minimist": "^1.2.8" + }, + "bin": { + "next-sitemap": "bin/next-sitemap.mjs", + "next-sitemap-cjs": "bin/next-sitemap.cjs" + }, + "engines": { + "node": ">=14.18" + }, + "peerDependencies": { + "next": "*" + } + }, + "node_modules/next-sitemap/node_modules/@next/env": { + "version": "13.5.11", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.11.tgz", + "integrity": "sha512-fbb2C7HChgM7CemdCY+y3N1n8pcTKdqtQLbC7/EQtPdLvlMUT9JX/dBYl8MMZAtYG4uVMyPFHXckb68q/NRwqg==", + "license": "MIT" + }, "node_modules/next-themes": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", @@ -11843,6 +12103,7 @@ "version": "1.6.7", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "devOptional": true, "license": "MIT" }, "node_modules/node-fetch/node_modules/tr46": { @@ -11970,17 +12231,6 @@ ], "license": "MIT" }, - "node_modules/ofetch": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", - "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", - "license": "MIT", - "dependencies": { - "destr": "^2.0.5", - "node-fetch-native": "^1.6.7", - "ufo": "^1.6.1" - } - }, "node_modules/ohash": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", @@ -12028,9 +12278,9 @@ } }, "node_modules/path-expression-matcher": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.1.3.tgz", - "integrity": "sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", "funding": [ { "type": "github", @@ -12396,12 +12646,41 @@ ], "license": "MIT" }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/random-word-slugs": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/random-word-slugs/-/random-word-slugs-0.1.7.tgz", "integrity": "sha512-8cyzxOIDeLFvwSPTgCItMXHGT5ZPkjhuFKUTww06Xg1dNMXuGxIKlARvS7upk6JXIm41ZKXmtlKR1iCRWklKmg==", "license": "MIT" }, + "node_modules/razorpay": { + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/razorpay/-/razorpay-2.9.6.tgz", + "integrity": "sha512-zsHAQzd6e1Cc6BNoCNZQaf65ElL6O6yw0wulxmoG5VQDr363fZC90Mp1V5EktVzG45yPyNomNXWlf4cQ3622gQ==", + "license": "MIT", + "dependencies": { + "axios": "^1.6.8" + } + }, "node_modules/rc9": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", @@ -12493,29 +12772,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/react-redux": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", - "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", - "license": "MIT", - "dependencies": { - "@types/use-sync-external-store": "^0.0.6", - "use-sync-external-store": "^1.4.0" - }, - "peerDependencies": { - "@types/react": "^18.2.25 || ^19", - "react": "^18.0 || ^19", - "redux": "^5.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, "node_modules/react-remove-scroll": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", @@ -12610,15 +12866,6 @@ } } }, - "node_modules/react-timeago": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/react-timeago/-/react-timeago-8.3.0.tgz", - "integrity": "sha512-BeR0hj/5qqTc2+zxzBSQZMky6MmqwOtKseU3CSmcjKR5uXerej2QY34v2d+cdz11PoeVfAdWLX+qjM/UdZkUUg==", - "license": "MIT", - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -12708,21 +12955,6 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, - "node_modules/redux": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" - }, - "node_modules/redux-thunk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", - "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", - "license": "MIT", - "peerDependencies": { - "redux": "^5.0.0" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12755,12 +12987,6 @@ "node": ">=9.3.0 || >=8.10.0 <9.0.0" } }, - "node_modules/reselect": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", - "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", - "license": "MIT" - }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -12791,6 +13017,16 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rolldown": { "version": "1.0.0-rc.9", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", @@ -12875,12 +13111,56 @@ "integrity": "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==", "license": "MIT" }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/schema-dts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-2.0.0.tgz", + "integrity": "sha512-t7NoCy3Rn5GHGx6p7s1qIYK/AeIb8ZxJNR9WUNFkwMv2CiiGZBmqqYWc2FlZVm5ZbiHMY4OvBWhj7QtyrFO2Jw==", + "license": "Apache-2.0", + "dependencies": { + "schema-dts-lib": "^1.0.0" + } + }, + "node_modules/schema-dts-lib": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-dts-lib/-/schema-dts-lib-1.0.0.tgz", + "integrity": "sha512-9MEO5vpQH9JdBioUupqluzxSYxPLjhmqRUudk15adUl/ypnRsM2/M1kN3AmVJQeG7nZqcL68H8JlGqQQT6vy9A==", + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + } + }, "node_modules/schema-utils": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", @@ -13074,16 +13354,6 @@ "node": ">=6" } }, - "node_modules/standardwebhooks": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", - "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", - "license": "MIT", - "dependencies": { - "@stablelib/base64": "^1.0.0", - "fast-sha256": "^1.3.0" - } - }, "node_modules/state-local": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", @@ -13162,9 +13432,9 @@ } }, "node_modules/strnum": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.1.tgz", - "integrity": "sha512-BwRvNd5/QoAtyW1na1y1LsJGQNvRlkde6Q/ipqqEaivoMdV+B1OMOTVdwR+N/cwVUcIt9PYyHmV8HyexCZSupg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", "funding": [ { "type": "github", @@ -13395,6 +13665,18 @@ "node": ">=14.0.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", @@ -13478,12 +13760,6 @@ "node": ">=14.17" } }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "license": "MIT" - }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", @@ -13991,6 +14267,21 @@ "node": ">=8" } }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 254fa74..38291a6 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "dev": "next dev --turbopack", "build": "prisma generate && next build --turbopack", + "postbuild": "next-sitemap", "start": "next start", "lint": "biome check", "format": "biome format --write", @@ -24,13 +25,12 @@ "@ai-sdk/openai": "^3.0.14", "@ai-sdk/perplexity": "^3.0.8", "@ai-sdk/xai": "^3.0.26", - "@azure/storage-blob": "^12.31.0", + "@aws-sdk/client-s3": "^3.1060.0", + "@aws-sdk/s3-request-presigner": "^3.1060.0", "@hookform/resolvers": "^5.2.2", "@inngest/realtime": "^0.4.5", "@monaco-editor/react": "^4.7.0", "@paralleldrive/cuid2": "^3.0.4", - "@polar-sh/better-auth": "^1.8.2", - "@polar-sh/sdk": "^0.46.3", "@prisma/client": "^6.17.1", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-alert-dialog": "^1.1.15", @@ -68,6 +68,7 @@ "@vercel/analytics": "^1.6.1", "@xyflow/react": "^12.9.2", "ai": "^6.0.45", + "bcryptjs": "^3.0.3", "better-auth": "^1.2.7", "class-variance-authority": "^0.7.1", "client-only": "^0.0.1", @@ -86,6 +87,7 @@ "lucide-react": "^0.546.0", "motion": "^12.29.0", "next": "^15.5.13", + "next-sitemap": "^4.2.3", "next-themes": "^0.4.6", "node-fetch": "^2.7.0", "nodemailer": "^7.0.11", @@ -93,6 +95,7 @@ "pg": "^8.20.0", "pg-cursor": "^2.12.1", "random-word-slugs": "^0.1.7", + "razorpay": "^2.9.6", "react": "19.1.0", "react-day-picker": "^9.11.1", "react-dom": "19.1.0", @@ -100,6 +103,7 @@ "react-hook-form": "^7.65.0", "react-resizable-panels": "^3.0.6", "recharts": "^2.15.4", + "schema-dts": "^2.0.0", "server-only": "^0.0.1", "sonner": "^2.0.7", "stripe": "^20.4.1", @@ -114,6 +118,7 @@ "devDependencies": { "@biomejs/biome": "2.2.0", "@tailwindcss/postcss": "^4", + "@types/bcryptjs": "^2.4.6", "@types/node": "^20", "@types/node-fetch": "^2.6.13", "@types/nodemailer": "^7.0.11", diff --git a/prisma/migrations/20260409154001_razorpay/migration.sql b/prisma/migrations/20260409154001_razorpay/migration.sql new file mode 100644 index 0000000..9fa243e --- /dev/null +++ b/prisma/migrations/20260409154001_razorpay/migration.sql @@ -0,0 +1,22 @@ +/* + Warnings: + + - A unique constraint covering the columns `[emailVerifyToken]` on the table `user` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "user" ADD COLUMN "emailVerifyAttempts" INTEGER NOT NULL DEFAULT 0, +ADD COLUMN "emailVerifyExpiry" TIMESTAMP(3), +ADD COLUMN "emailVerifyToken" TEXT; + +-- DropEnum +DROP TYPE "FilterOperation"; + +-- CreateIndex +CREATE INDEX "AggregateNode_nodeId_idx" ON "AggregateNode"("nodeId"); + +-- CreateIndex +CREATE INDEX "PostgresNode_nodeId_idx" ON "PostgresNode"("nodeId"); + +-- CreateIndex +CREATE UNIQUE INDEX "user_emailVerifyToken_key" ON "user"("emailVerifyToken"); diff --git a/prisma/migrations/20260409_add_razorpay_billing/migration.sql b/prisma/migrations/20260409_add_razorpay_billing/migration.sql new file mode 100644 index 0000000..7585365 --- /dev/null +++ b/prisma/migrations/20260409_add_razorpay_billing/migration.sql @@ -0,0 +1,36 @@ +-- Add Razorpay billing fields to User table +ALTER TABLE "user" + ADD COLUMN IF NOT EXISTS "plan" TEXT NOT NULL DEFAULT 'FREE', + ADD COLUMN IF NOT EXISTS "planStatus" TEXT NOT NULL DEFAULT 'active', + ADD COLUMN IF NOT EXISTS "razorpayCustomerId" TEXT UNIQUE, + ADD COLUMN IF NOT EXISTS "razorpaySubId" TEXT UNIQUE, + ADD COLUMN IF NOT EXISTS "currentPeriodEnd" TIMESTAMP(3), + ADD COLUMN IF NOT EXISTS "cancelAtPeriodEnd" BOOLEAN NOT NULL DEFAULT false, + ADD COLUMN IF NOT EXISTS "workflowRunsUsed" INTEGER NOT NULL DEFAULT 0, + ADD COLUMN IF NOT EXISTS "workflowRunsReset" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- Create BillingEvent table for audit trail +CREATE TABLE IF NOT EXISTS "BillingEvent" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "type" TEXT NOT NULL, + "razorpayEventId" TEXT UNIQUE, + "amount" INTEGER, + "currency" TEXT NOT NULL DEFAULT 'INR', + "plan" TEXT, + "status" TEXT NOT NULL, + "rawPayload" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "BillingEvent_pkey" PRIMARY KEY ("id") +); + +CREATE INDEX IF NOT EXISTS "BillingEvent_userId_idx" ON "BillingEvent"("userId"); +CREATE INDEX IF NOT EXISTS "BillingEvent_type_idx" ON "BillingEvent"("type"); + +ALTER TABLE "BillingEvent" + ADD CONSTRAINT "BillingEvent_userId_fkey" + FOREIGN KEY ("userId") REFERENCES "user"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + +-- Existing users stay on FREE plan +UPDATE "user" SET "plan" = 'FREE' WHERE "plan" IS NULL OR "plan" = ''; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8012a75..46cc3e9 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -19,7 +19,10 @@ model User { id String @id name String email String - emailVerified Boolean @default(false) + emailVerified Boolean @default(false) + emailVerifyToken String? @unique + emailVerifyExpiry DateTime? + emailVerifyAttempts Int @default(0) image String? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -30,10 +33,39 @@ model User { executionCount Int @default(0) executionResetAt DateTime @default(now()) + // ── Subscription / Billing ─────────────────────────────────────────────── + plan String @default("FREE") // FREE|STARTER|PRO|TEAM + planStatus String @default("active") // active|past_due|cancelled|paused + razorpayCustomerId String? @unique // cust_xxxx + razorpaySubId String? @unique // sub_xxxx + currentPeriodEnd DateTime? + cancelAtPeriodEnd Boolean @default(false) + workflowRunsUsed Int @default(0) + workflowRunsReset DateTime @default(now()) + billingEvents BillingEvent[] + @@unique([email]) @@map("user") } +model BillingEvent { + id String @id @default(cuid()) + userId String + type String // subscription.activated | payment.captured | subscription.cancelled | etc. + razorpayEventId String? @unique + amount Int? // paise + currency String @default("INR") + plan String? + status String // success | failed | pending + rawPayload String @db.Text // full Razorpay webhook JSON + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@index([userId]) + @@index([type]) +} + model Session { id String @id expiresAt DateTime diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..890653a --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,12 @@ +{ + "name": "Nodebase", + "short_name": "Nodebase", + "description": "Workflow automation for India", + "start_url": "/", + "display": "standalone", + "background_color": "#111111", + "theme_color": "#F97316", + "icons": [ + { "src": "/logos/logo.svg", "sizes": "any", "type": "image/svg+xml" } + ] +} diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..f3d360a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,20 @@ +# * +User-agent: * +Allow: / +Disallow: /workflows/ +Disallow: /editor/ +Disallow: /settings/ +Disallow: /api/ + +# Googlebot +User-agent: Googlebot +Allow: / +Disallow: /workflows/ +Disallow: /editor/ +Disallow: /settings/ + +# Host +Host: https://nodebase.tech + +# Sitemaps +Sitemap: https://nodebase.tech/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..94c903b --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,33 @@ + + +https://nodebase.tech/sentry-example-page2026-06-03T17:28:28.119Zweekly0.7 +https://nodebase.tech/docs/nodes/loop2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/msg912026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/getting-started2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/razorpay-trigger2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/switch2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/code2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/if-else2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/razorpay2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/set-variable2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/error-trigger2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/shiprocket2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/whatsapp-trigger2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/slack2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/ai2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/http-request2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/whatsapp2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/pricing2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/merge2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/google-sheets2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/notion2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/wait2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes/gmail2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/docs/nodes2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/blog2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/integrations2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/login2026-06-03T17:28:28.120Zweekly0.7 +https://nodebase.tech/signup2026-06-03T17:28:28.120Zweekly0.7 + \ No newline at end of file diff --git a/scripts/create-razorpay-plans.ts b/scripts/create-razorpay-plans.ts new file mode 100644 index 0000000..3b909d1 --- /dev/null +++ b/scripts/create-razorpay-plans.ts @@ -0,0 +1,74 @@ +import Razorpay from "razorpay" +import { PRICE_CATALOG } from "../src/config/pricing" + +async function createPlans() { + if (!process.env.RAZORPAY_KEY_ID || !process.env.RAZORPAY_KEY_SECRET) { + console.error("Set RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET in .env first") + process.exit(1) + } + + const razorpay = new Razorpay({ + key_id: process.env.RAZORPAY_KEY_ID, + key_secret: process.env.RAZORPAY_KEY_SECRET, + }) + + const plans: Array<{ + period: "monthly" + interval: number + item: { name: string; amount: number; currency: string; description: string } + }> = [ + { + period: "monthly", + interval: 1, + item: { + name: "Nodebase Starter", + amount: PRICE_CATALOG.STARTER.monthly * 100, // in paise + currency: "INR", + description: "10,000 workflow runs/month, 50 workflows", + }, + }, + { + period: "monthly", + interval: 1, + item: { + name: "Nodebase Pro", + amount: PRICE_CATALOG.PRO.monthly * 100, // in paise + currency: "INR", + description: "100,000 workflow runs/month, unlimited workflows", + }, + }, + { + period: "monthly", + interval: 1, + item: { + name: "Nodebase Team", + amount: PRICE_CATALOG.TEAM.monthly * 100, // in paise + currency: "INR", + description: "500,000 workflow runs/month, team features", + }, + }, + ] + + for (const plan of plans) { + const tierName = plan.item.name.split(" ")[1].toUpperCase() + const envVarName = `RAZORPAY_PLAN_${tierName}_ID` + + if (process.env[envVarName]) { + console.log(`Plan '${plan.item.name}' already exists via env ${envVarName} → ID: ${process.env[envVarName]}`) + console.log("") + continue + } + + const created = (await razorpay.plans.create(plan)) as unknown as { id: string } + console.log(`Created plan: ${plan.item.name} → ID: ${created.id}`) + console.log(`Add to .env: ${envVarName}=${created.id}`) + console.log("") + } + + console.log("Done! Copy the plan IDs above into your .env file.") +} + +createPlans().catch((err) => { + console.error(err) + process.exit(1) +}) diff --git a/src/app/(auth)/check-email/page.tsx b/src/app/(auth)/check-email/page.tsx new file mode 100644 index 0000000..d509d17 --- /dev/null +++ b/src/app/(auth)/check-email/page.tsx @@ -0,0 +1,53 @@ +"use client" + +import Link from "next/link" +import { Suspense, useEffect, useState } from "react" +import { MailCheck } from "lucide-react" + +function CheckEmailContent() { + const [email, setEmail] = useState(null) + + useEffect(() => { + setEmail(sessionStorage.getItem("pendingEmail")) + }, []) + + return ( +
+
+
+
+ +
+

+ Check your inbox +

+

+ We sent a verification link to
+ {email || "your email address"} +

+
+

+ Didn't receive it? Check your spam folder or{" "} + + request a new link + . +

+
+
+ + Return to login + +
+
+
+
+ ) +} + +export default function CheckEmailPage() { + return ( + + + + ) +} diff --git a/src/app/(auth)/resend-verification/page.tsx b/src/app/(auth)/resend-verification/page.tsx new file mode 100644 index 0000000..555eb50 --- /dev/null +++ b/src/app/(auth)/resend-verification/page.tsx @@ -0,0 +1,101 @@ +"use client" + +import { useState } from "react" +import { useForm } from "react-hook-form" +import { z } from "zod" +import { zodResolver } from "@hookform/resolvers/zod" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { toast } from "sonner" +import Link from "next/link" + +const resendSchema = z.object({ + email: z.string().email("Please enter a valid email address"), +}) + +export default function ResendVerificationPage() { + const [success, setSuccess] = useState(false) + + const form = useForm>({ + resolver: zodResolver(resendSchema), + defaultValues: { email: "" }, + }) + + const onSubmit = async (values: z.infer) => { + try { + const res = await fetch("/api/auth/resend-verification", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(values), + }) + const data = await res.json() + + if (res.ok) { + setSuccess(true) + } else { + toast.error(data.error || "Failed to resend verification email") + } + } catch (err) { + toast.error("Network error. Please try again.") + } + } + + const isPending = form.formState.isSubmitting + + return ( +
+ + + Resend Verification + + Enter your email to receive a new verification link + + + + {success ? ( +
+
+

Email Sent

+

+ If an account exists for {form.getValues().email}, we've sent a new verification link. +

+ +
+ ) : ( +
+ + ( + + Email address + + + + + + )} + /> + + + + )} +
+
+
+ ) +} diff --git a/src/app/(auth)/verify-email/page.tsx b/src/app/(auth)/verify-email/page.tsx new file mode 100644 index 0000000..5422138 --- /dev/null +++ b/src/app/(auth)/verify-email/page.tsx @@ -0,0 +1,92 @@ +"use client" + +import { useSearchParams, useRouter } from "next/navigation" +import { useEffect, useState, Suspense } from "react" +import Link from "next/link" + +function VerifyEmailContent() { + const searchParams = useSearchParams() + const router = useRouter() + const token = searchParams.get("token") + + const [status, setStatus] = useState<"loading" | "success" | "error" | "expired">("loading") + const [message, setMessage] = useState("") + + useEffect(() => { + if (!token) { + setStatus("error") + setMessage("No verification token found. Check your email for the correct link.") + return + } + + // Call the verify API + fetch("/api/auth/verify-email", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ token }), + }) + .then(res => res.json()) + .then(data => { + if (data.success) { + setStatus("success") + setMessage("Email verified! Redirecting to login...") + setTimeout(() => router.push("/login?verified=true"), 2000) + } else if (data.error === "TOKEN_EXPIRED") { + setStatus("expired") + setMessage("This verification link has expired. Request a new one below.") + } else { + setStatus("error") + setMessage(data.error || "Verification failed. The link may be invalid.") + } + }) + .catch(() => { + setStatus("error") + setMessage("Network error. Please try again.") + }) + }, [token, router]) + + return ( +
+
+ {status === "loading" && ( + <> +
+

Verifying your email...

+ + )} + {status === "success" && ( + <> +
+

Email Verified!

+

{message}

+ + )} + {(status === "error" || status === "expired") && ( + <> +
+

+ {status === "expired" ? "Link Expired" : "Verification Failed"} +

+

{message}

+ + Resend Verification Email + + + )} +
+
+ ) +} + +export default function VerifyEmailPage() { + return ( + + + + ) +} diff --git a/src/app/(marketing)/pricing/page.tsx b/src/app/(marketing)/pricing/page.tsx new file mode 100644 index 0000000..513b8a0 --- /dev/null +++ b/src/app/(marketing)/pricing/page.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from "next" +import { PricingPage } from "./pricing-page" + +export const metadata: Metadata = { + title: "Pricing", + description: + "Simple, transparent pricing for Nodebase workflow automation. " + + "Start free, upgrade when you grow. Plans for indie hackers, startups, and teams.", + openGraph: { + title: "Pricing — Nodebase", + description: + "Simple, transparent pricing. Start free, upgrade when you grow.", + }, +} + +export default function Page() { + return +} diff --git a/src/app/(marketing)/pricing/pricing-page.tsx b/src/app/(marketing)/pricing/pricing-page.tsx new file mode 100644 index 0000000..6311ecf --- /dev/null +++ b/src/app/(marketing)/pricing/pricing-page.tsx @@ -0,0 +1,347 @@ +"use client" + +import { PLAN_LIMITS } from "@/lib/plan-limits" +import { CheckIcon, XIcon, ZapIcon, SparklesIcon, ArrowRightIcon } from "lucide-react" +import Link from "next/link" +import { useState } from "react" +import { PRICE_CATALOG } from "@/config/pricing" + +/* ─── plan data ──────────────────────────────────────────── */ + +type Interval = "monthly" | "yearly" + +interface PlanCard { + key: string + name: string + tagline: string + monthlyPrice: number | null // null = custom + yearlyPrice: number | null + cta: string + ctaHref: string + featured: boolean + features: string[] + notIncluded?: string[] +} + +const plans: PlanCard[] = [ + { + key: "FREE", + name: "Free", + tagline: "For side projects & experiments", + monthlyPrice: PRICE_CATALOG.FREE.monthly, + yearlyPrice: PRICE_CATALOG.FREE.yearly, + cta: "Get Started Free", + ctaHref: "/signup", + featured: false, + features: [ + `${PLAN_LIMITS.FREE.runs.toLocaleString()} workflow runs / mo`, + `${PLAN_LIMITS.FREE.workflows} workflows`, + "All core nodes", + "Community support", + ], + notIncluded: ["Priority support", "Custom nodes", "Team collaboration"], + }, + { + key: "STARTER", + name: "Starter", + tagline: "For indie hackers & small biz", + monthlyPrice: PRICE_CATALOG.STARTER.monthly, + yearlyPrice: PRICE_CATALOG.STARTER.yearly, + cta: "Start 14-day Trial", + ctaHref: "/signup?plan=starter", + featured: false, + features: [ + `${PLAN_LIMITS.STARTER.runs.toLocaleString()} workflow runs / mo`, + `${PLAN_LIMITS.STARTER.workflows} workflows`, + "All core + premium nodes", + "Email support", + "Webhook triggers", + "Execution history — 30 days", + ], + notIncluded: ["Custom nodes", "Team collaboration"], + }, + { + key: "PRO", + name: "Pro", + tagline: "For growing startups & D2C brands", + monthlyPrice: PRICE_CATALOG.PRO.monthly, + yearlyPrice: PRICE_CATALOG.PRO.yearly, + cta: "Start 14-day Trial", + ctaHref: "/signup?plan=pro", + featured: true, + features: [ + `${PLAN_LIMITS.PRO.runs.toLocaleString()} workflow runs / mo`, + "Unlimited workflows", + "All nodes incl. AI nodes", + "Priority email & chat support", + "Webhook triggers", + "Execution history — 90 days", + "Custom branding", + ], + notIncluded: ["Team collaboration"], + }, + { + key: "TEAM", + name: "Team", + tagline: "For teams & agencies", + monthlyPrice: PRICE_CATALOG.TEAM.monthly, + yearlyPrice: PRICE_CATALOG.TEAM.yearly, + cta: "Contact Sales", + ctaHref: "/signup?plan=team", + featured: false, + features: [ + `${PLAN_LIMITS.TEAM.runs.toLocaleString()} workflow runs / mo`, + "Unlimited workflows", + "Everything in Pro", + "Team collaboration", + "Dedicated account manager", + "Execution history — 1 year", + "SLA guarantee", + "Custom integrations", + ], + }, +] + +const faqs = [ + { + q: "Can I change plans later?", + a: "Yes — upgrade, downgrade, or cancel anytime. Changes take effect at the next billing cycle.", + }, + { + q: "What happens when I hit my run limit?", + a: "Workflows will pause until the next month or until you upgrade. No data is lost.", + }, + { + q: "Do you support Indian payment methods?", + a: "Absolutely. We use Razorpay — pay with UPI, cards, net-banking, or wallets.", + }, + { + q: "Is there a free trial?", + a: "Paid plans include a 14-day free trial. No credit card required to start.", + }, + { + q: "Can I get a refund?", + a: "We offer a 30-day money-back guarantee on all paid plans. No questions asked.", + }, +] + +/* ─── component ──────────────────────────────────────────── */ + +export function PricingPage() { + const [interval, setInterval] = useState("monthly") + + return ( +
+ {/* ── Nav ─── */} + + + {/* ── Hero ─── */} +
+
+ + Simple, transparent pricing +
+

+ Plans that scale{" "} + + with you + +

+

+ Start free—no credit card needed. +
Upgrade when your automation needs grow. +

+
+ + {/* ── Interval toggle ─── */} +
+
+ + + {/* sliding pill */} + +
+
+ + {/* ── Cards ─── */} +
+
+ {plans.map((plan) => { + const price = interval === "monthly" ? plan.monthlyPrice : plan.yearlyPrice + const isFree = price === 0 + + return ( +
+ {plan.featured && ( +
+ Most Popular +
+ )} + + {/* header */} +
+

{plan.name}

+

{plan.tagline}

+
+ + {/* price */} +
+ {isFree ? ( +
+ ₹0 + / forever +
+ ) : price != null ? ( +
+ + ₹{price.toLocaleString("en-IN")} + + / mo +
+ ) : ( +
Custom
+ )} + {!isFree && interval === "yearly" && price != null && ( +

+ Billed ₹{(price * 12).toLocaleString("en-IN")} / year +

+ )} +
+ + {/* CTA */} + + {plan.cta} + + + + {/* features */} +
    + {plan.features.map((f) => ( +
  • + + {f} +
  • + ))} + {plan.notIncluded?.map((f) => ( +
  • + + {f} +
  • + ))} +
+
+ ) + })} +
+
+ + {/* ── FAQ ─── */} +
+
+

+ Frequently asked questions +

+
+ {faqs.map((faq) => ( +
+ + {faq.q} + + + + + +

+ {faq.a} +

+
+ ))} +
+
+
+ + {/* ── Bottom CTA ─── */} +
+
+

Ready to automate?

+

+ Join thousands of Indian businesses running on Nodebase. +

+ + Get Started Free + + +
+
+ + {/* ── Footer ─── */} +
+ © {new Date().getFullYear()} Nodebase. All rights reserved. +
+
+ ) +} diff --git a/src/app/api/auth/custom-signup/route.ts b/src/app/api/auth/custom-signup/route.ts new file mode 100644 index 0000000..54a80ca --- /dev/null +++ b/src/app/api/auth/custom-signup/route.ts @@ -0,0 +1,89 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/db" +import { generateVerifyToken, getTokenExpiry, sendVerificationEmail } from "@/lib/email-verification" +import { hash } from "bcryptjs" +import { createId } from "@paralleldrive/cuid2" + +export async function POST(req: NextRequest) { + try { + const body = await req.json() + const { email, password, name } = body + + if (!email || !password) { + return NextResponse.json({ error: "Missing email or password" }, { status: 400 }) + } + + // 1. Check if email already exists + const existing = await prisma.user.findUnique({ where: { email } }) + if (existing) { + if (existing.emailVerified) { + return NextResponse.json({ error: "An account with this email already exists." }, { status: 400 }) + } else { + if (existing.emailVerifyAttempts >= 5) { + return NextResponse.json({ error: "Too many verification attempts. Try again later." }, { status: 429 }) + } + // Resend verification to unverified account + const token = generateVerifyToken() + await prisma.user.update({ + where: { email }, + data: { + emailVerifyToken: token, + emailVerifyExpiry: getTokenExpiry(), + }, + }) + try { + await sendVerificationEmail(email, existing.name || email, token) + } catch (emailError) { + console.error("Failed to send verification email:", emailError) + } + return NextResponse.json({ success: "VERIFICATION_SENT", email }) + } + } + + // 2. Hash password + const hashedPassword = await hash(password, 12) + + // 3. Generate token + const verifyToken = generateVerifyToken() + const verifyExpiry = getTokenExpiry() + + // 4. Create user — NOT verified yet + // Since we're partially bypassing better-auth for custom signup, we must create Account records for passwords manually or just rely on better-auth's adapter if we sign in email later. + // Actually better-auth natively stores password in `Account` model. + // Let's create the User first. + const user = await prisma.user.create({ + data: { + id: createId(), + email, + name: name || email.split("@")[0], + emailVerified: false, + emailVerifyToken: verifyToken, + emailVerifyExpiry: verifyExpiry, + }, + }) + + // Also create account for password login + await prisma.account.create({ + data: { + id: createId(), + userId: user.id, + accountId: email, + providerId: "credential", + password: hashedPassword, + } + }) + + // 5. Send verification email (non-blocking) + try { + await sendVerificationEmail(email, user.name || email, verifyToken) + } catch (emailError) { + console.error("Failed to send verification email:", emailError) + } + + // 6. DO NOT log them in — return success directive + return NextResponse.json({ success: "VERIFICATION_SENT", email }) + } catch (error) { + console.error("Signup error:", error) + return NextResponse.json({ error: "Internal server error" }, { status: 500 }) + } +} diff --git a/src/app/api/auth/resend-verification/route.ts b/src/app/api/auth/resend-verification/route.ts new file mode 100644 index 0000000..3f2d8be --- /dev/null +++ b/src/app/api/auth/resend-verification/route.ts @@ -0,0 +1,45 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/db" +import { generateVerifyToken, getTokenExpiry, sendResendVerificationEmail } from "@/lib/email-verification" + +export async function POST(req: NextRequest) { + try { + const { email } = await req.json() as { email: string } + + const user = await prisma.user.findUnique({ where: { email } }) + + // Always return success to prevent email enumeration attacks + if (!user || user.emailVerified) { + return NextResponse.json({ success: true }) + } + + // Rate limit: max 3 resends per user + if (user.emailVerifyAttempts >= 3) { + return NextResponse.json( + { error: "Too many resend attempts. Please contact support." }, + { status: 429 } + ) + } + + const token = generateVerifyToken() + + await prisma.user.update({ + where: { id: user.id }, + data: { + emailVerifyToken: token, + emailVerifyExpiry: getTokenExpiry(), + emailVerifyAttempts: { increment: 1 }, + }, + }) + + await sendResendVerificationEmail(email, user.name || email, token) + + return NextResponse.json({ success: true }) + } catch (error) { + console.error("Resend verification error:", error) + return NextResponse.json( + { error: "Server error. Please try again." }, + { status: 500 } + ) + } +} diff --git a/src/app/api/auth/verify-email/route.ts b/src/app/api/auth/verify-email/route.ts new file mode 100644 index 0000000..4e63ac8 --- /dev/null +++ b/src/app/api/auth/verify-email/route.ts @@ -0,0 +1,58 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/db" + +export async function POST(req: NextRequest) { + try { + const { token } = await req.json() as { token: string } + + if (!token || typeof token !== "string") { + return NextResponse.json( + { error: "Invalid token" }, + { status: 400 } + ) + } + + const user = await prisma.user.findUnique({ + where: { emailVerifyToken: token }, + }) + + if (!user) { + return NextResponse.json( + { error: "Invalid or already used verification link." }, + { status: 400 } + ) + } + + if (user.emailVerified) { + return NextResponse.json( + { success: true, message: "Already verified" } + ) + } + + if (!user.emailVerifyExpiry || user.emailVerifyExpiry < new Date()) { + return NextResponse.json( + { error: "TOKEN_EXPIRED" }, + { status: 400 } + ) + } + + // Mark as verified — clear the token + await prisma.user.update({ + where: { id: user.id }, + data: { + emailVerified: true, + emailVerifyToken: null, + emailVerifyExpiry: null, + emailVerifyAttempts: 0, + }, + }) + + return NextResponse.json({ success: true }) + } catch (error) { + console.error("Email verification error:", error) + return NextResponse.json( + { error: "Server error. Please try again." }, + { status: 500 } + ) + } +} diff --git a/src/app/api/polar/webhook/route.ts b/src/app/api/polar/webhook/route.ts deleted file mode 100644 index b746c8f..0000000 --- a/src/app/api/polar/webhook/route.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { NextRequest, NextResponse } from "next/server" -import { validateEvent, WebhookVerificationError } from "@polar-sh/sdk/webhooks" -import prisma from "@/lib/db" - -export async function POST(req: NextRequest) { - const body = await req.text() - const webhookHeaders: Record = {} - req.headers.forEach((value, key) => { - webhookHeaders[key] = value - }) - const secret = process.env.POLAR_WEBHOOK_SECRET ?? "" - - let event: ReturnType - try { - event = validateEvent(body, webhookHeaders, secret) - } catch (error) { - if (error instanceof WebhookVerificationError) { - return NextResponse.json({ error: "Invalid signature" }, { status: 400 }) - } - return NextResponse.json({ error: "Invalid webhook" }, { status: 400 }) - } - - switch (event.type) { - case "subscription.created": - case "subscription.updated": { - const sub = event.data - const userId = sub.customer?.externalId - if (!userId) break - await prisma.user.update({ - where: { id: userId }, - data: { executionCount: 0, executionResetAt: new Date() }, - }) - break - } - case "subscription.canceled": - case "subscription.revoked": { - // Subscription ended — user goes back to free tier - // No action needed, the execution gate handles it - break - } - } - - return NextResponse.json({ received: true }) -} diff --git a/src/app/api/webhooks/razorpay-billing/route.ts b/src/app/api/webhooks/razorpay-billing/route.ts new file mode 100644 index 0000000..45971d1 --- /dev/null +++ b/src/app/api/webhooks/razorpay-billing/route.ts @@ -0,0 +1,281 @@ +import { NextRequest, NextResponse } from "next/server" +import crypto from "crypto" +import prisma from "@/lib/db" + +function verifyWebhookSignature( + body: string, + signature: string, + secret: string +): boolean { + try { + const expected = crypto + .createHmac("sha256", secret) + .update(body) + .digest("hex") + + if (expected.length !== signature.length) return false + + return crypto.timingSafeEqual( + Buffer.from(expected, "hex"), + Buffer.from(signature, "hex") + ) + } catch { + return false + } +} + +export async function POST(req: NextRequest) { + const secret = process.env.RAZORPAY_WEBHOOK_SECRET + if (!secret) { + console.error("RAZORPAY_WEBHOOK_SECRET not set") + return NextResponse.json({ error: "Misconfigured" }, { status: 500 }) + } + + const signature = req.headers.get("x-razorpay-signature") || "" + const rawBody = await req.text() + + // ── Verify signature — CRITICAL security check ────────────────────────── + if (!verifyWebhookSignature(rawBody, signature, secret)) { + console.error("Razorpay webhook: Invalid signature") + return NextResponse.json({ error: "Invalid signature" }, { status: 401 }) + } + + let event: Record + try { + event = JSON.parse(rawBody) as Record + } catch { + return NextResponse.json({ error: "Invalid JSON" }, { status: 400 }) + } + + const eventType = event.event as string + const payload = event.payload as Record + + console.log(`Razorpay billing webhook received: ${eventType}`) + + try { + switch (eventType) { + // ── Subscription activated (first payment succeeded) ───────────────── + case "subscription.activated": { + const sub = ( + payload.subscription as Record + )?.entity as Record + const subId = sub?.id as string + const notes = sub?.notes as Record + const userId = notes?.userId + + if (!userId) { + console.error("subscription.activated: no userId in notes") + break + } + + const plan = (notes?.plan || "FREE") as string + const periodEnd = sub?.current_end + ? new Date((sub.current_end as number) * 1000) + : null + + await prisma.user.update({ + where: { id: userId }, + data: { + plan, + planStatus: "active", + razorpaySubId: subId, + currentPeriodEnd: periodEnd, + cancelAtPeriodEnd: false, + }, + }) + + await prisma.billingEvent.create({ + data: { + userId, + type: eventType, + razorpayEventId: + (event.account_id as string) || `${subId}-activated`, + plan, + status: "success", + rawPayload: rawBody, + }, + }) + + console.log(`User ${userId} activated ${plan} plan`) + break + } + + // ── Payment captured (recurring monthly payment) ───────────────────── + case "subscription.charged": + case "payment.captured": { + const payment = ( + payload.payment as Record + )?.entity as Record + const subId = payment?.subscription_id as string | undefined + const amount = payment?.amount as number | undefined + + if (!subId) break + + const user = await prisma.user.findFirst({ + where: { razorpaySubId: subId }, + }) + + if (!user) { + console.error(`payment.captured: no user found for sub ${subId}`) + break + } + + // Extend subscription period by 1 month + const newPeriodEnd = new Date() + newPeriodEnd.setMonth(newPeriodEnd.getMonth() + 1) + + await prisma.user.update({ + where: { id: user.id }, + data: { + planStatus: "active", + currentPeriodEnd: newPeriodEnd, + // Reset monthly run counter on successful renewal + workflowRunsUsed: 0, + workflowRunsReset: new Date(), + }, + }) + + await prisma.billingEvent.create({ + data: { + userId: user.id, + type: eventType, + razorpayEventId: payment?.id as string, + amount: amount ?? null, + plan: user.plan, + status: "success", + rawPayload: rawBody, + }, + }) + + console.log( + `User ${user.id} payment captured ₹${(amount ?? 0) / 100}` + ) + break + } + + // ── Payment failed ──────────────────────────────────────────────────── + case "payment.failed": { + const payment = ( + payload.payment as Record + )?.entity as Record + const subId = payment?.subscription_id as string | undefined + if (!subId) break + + const user = await prisma.user.findFirst({ + where: { razorpaySubId: subId }, + }) + if (!user) break + + await prisma.user.update({ + where: { id: user.id }, + data: { planStatus: "past_due" }, + }) + + await prisma.billingEvent.create({ + data: { + userId: user.id, + type: eventType, + razorpayEventId: payment?.id as string, + plan: user.plan, + status: "failed", + rawPayload: rawBody, + }, + }) + + console.log( + `User ${user.id} payment failed — status set to past_due` + ) + break + } + + // ── Subscription cancelled ──────────────────────────────────────────── + case "subscription.cancelled": { + const sub = ( + payload.subscription as Record + )?.entity as Record + const subId = sub?.id as string + const notes = sub?.notes as Record | undefined + let userId = notes?.userId + + if (!userId) { + const user = await prisma.user.findFirst({ + where: { razorpaySubId: subId }, + }) + if (!user) break + userId = user.id + } + + await prisma.user.update({ + where: { id: userId }, + data: { + plan: "FREE", + planStatus: "cancelled", + razorpaySubId: null, + currentPeriodEnd: null, + cancelAtPeriodEnd: false, + }, + }) + + await prisma.billingEvent.create({ + data: { + userId, + type: eventType, + razorpayEventId: subId, + status: "success", + rawPayload: rawBody, + }, + }) + + console.log( + `Subscription ${subId} cancelled — user downgraded to FREE` + ) + break + } + + // ── Subscription paused ─────────────────────────────────────────────── + case "subscription.paused": { + const sub = ( + payload.subscription as Record + )?.entity as Record + const subId = sub?.id as string + const user = await prisma.user.findFirst({ + where: { razorpaySubId: subId }, + }) + if (!user) break + + await prisma.user.update({ + where: { id: user.id }, + data: { planStatus: "paused" }, + }) + break + } + + // ── Subscription resumed ────────────────────────────────────────────── + case "subscription.resumed": { + const sub = ( + payload.subscription as Record + )?.entity as Record + const subId = sub?.id as string + const user = await prisma.user.findFirst({ + where: { razorpaySubId: subId }, + }) + if (!user) break + + await prisma.user.update({ + where: { id: user.id }, + data: { planStatus: "active" }, + }) + break + } + + default: + console.log(`Unhandled billing webhook event: ${eventType}`) + } + } catch (error) { + console.error(`Error handling billing webhook ${eventType}:`, error) + // Return 200 so Razorpay doesn't retry — log the error for investigation + } + + // Always return 200 to Razorpay — never 4xx/5xx (causes retries) + return NextResponse.json({ received: true }) +} diff --git a/src/app/globals.css b/src/app/globals.css index 7a2796f..8c09747 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -151,63 +151,84 @@ } .dark { - --background: oklch(0.2598 0.0306 262.6666); - --foreground: oklch(0.9219 0 0); - --card: oklch(0.3106 0.0301 268.6365); - --card-foreground: oklch(0.9219 0 0); - --popover: oklch(0.29 0.0249 268.3986); - --popover-foreground: oklch(0.9219 0 0); + /* Pure black base - clean, professional */ + --background: oklch(0.17 0 0); + --foreground: oklch(0.95 0 0); + --card: oklch(0.2 0 0); + --card-foreground: oklch(0.95 0 0); + --popover: oklch(0.18 0 0); + --popover-foreground: oklch(0.95 0 0); + + /* Brand (orange stays the same in dark mode) */ --primary: oklch(0.6397 0.172 36.4421); --primary-foreground: oklch(1 0 0); - --secondary: oklch(0.3095 0.0266 266.7132); - --secondary-foreground: oklch(0.9219 0 0); - --muted: oklch(0.3095 0.0266 266.7132); - --muted-foreground: oklch(0.7155 0 0); - --accent: oklch(0.338 0.0589 267.5867); - --accent-foreground: oklch(0.8823 0.0571 254.1284); + + /* Surfaces */ + --secondary: oklch(0.24 0 0); + --secondary-foreground: oklch(0.95 0 0); + --muted: oklch(0.24 0 0); + --muted-foreground: oklch(0.65 0 0); + --accent: oklch(0.26 0 0); + --accent-foreground: oklch(0.95 0 0); + + /* Destructive */ --destructive: oklch(0.6368 0.2078 25.3313); - --border: oklch(0.3843 0.0301 269.7337); - --input: oklch(0.3843 0.0301 269.7337); + --destructive-foreground: oklch(1 0 0); + + /* Lines and inputs */ + --border: oklch(0.3 0 0); + --input: oklch(0.3 0 0); --ring: oklch(0.6397 0.172 36.4421); + + /* Charts */ --chart-1: oklch(0.7156 0.0605 248.6845); --chart-2: oklch(0.7693 0.0876 34.1875); --chart-3: oklch(0.5778 0.0759 254.1573); --chart-4: oklch(0.5016 0.0849 259.4902); --chart-5: oklch(0.425241 0.0952 264.0306); - --sidebar: oklch(0.31 0.0283 267.7408); - --sidebar-foreground: oklch(0.9219 0 0); + + /* Sidebar - slightly darker than main bg */ + --sidebar: oklch(0.14 0 0); + --sidebar-foreground: oklch(0.95 0 0); --sidebar-primary: oklch(0.6397 0.172 36.4421); --sidebar-primary-foreground: oklch(1 0 0); - --sidebar-accent: oklch(0.338 0.0589 267.5867); - --sidebar-accent-foreground: oklch(0.8823 0.0571 254.1284); - --sidebar-border: oklch(0.3843 0.0301 269.7337); + --sidebar-accent: oklch(0.22 0 0); + --sidebar-accent-foreground: oklch(0.95 0 0); + --sidebar-border: oklch(0.3 0 0); --sidebar-ring: oklch(0.6397 0.172 36.4421); - --destructive-foreground: oklch(1 0 0); + + /* Orange brand (same as :root) */ + --orange: #F97316; + --orange-dim: #EA6C0A; + --orange-glow: rgba(249,115,22,0.22); + --orange-subtle: rgba(249,115,22,0.09); + + /* Keep all utility vars */ --radius: 0.425rem; --font-sans: Inter, sans-serif; --font-serif: Source Serif 4, serif; --font-mono: JetBrains Mono, monospace; --shadow-color: hsl(0 0% 0%); - --shadow-opacity: 0.1; + --shadow-opacity: 0.15; --shadow-blur: 3px; --shadow-spread: 0px; --shadow-offset-x: 0px; --shadow-offset-y: 1px; --letter-spacing: 0em; --spacing: 0.25rem; - --shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), - 0px 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), - 0px 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), - 0px 2px 4px -1px hsl(0 0% 0% / 0.1); - --shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), - 0px 4px 6px -1px hsl(0 0% 0% / 0.1); - --shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), - 0px 8px 10px -1px hsl(0 0% 0% / 0.1); - --shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.25); + --shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.15); + --shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.15); + --shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.2), + 0px 1px 2px -1px hsl(0 0% 0% / 0.2); + --shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.2), + 0px 1px 2px -1px hsl(0 0% 0% / 0.2); + --shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.2), + 0px 2px 4px -1px hsl(0 0% 0% / 0.2); + --shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.2), + 0px 4px 6px -1px hsl(0 0% 0% / 0.2); + --shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.2), + 0px 8px 10px -1px hsl(0 0% 0% / 0.2); + --shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.35); } @layer base { @@ -297,4 +318,39 @@ .orange-dot-pulse { animation: orangeDot 1.8s ease-in-out infinite; +} + +/* Dark mode logo visibility */ +.dark .dark-invert { + filter: invert(1); +} + +.dark .dark-brightness { + filter: brightness(0) invert(1); +} + +/* Smooth scroll globally */ +html { + scroll-behavior: smooth; +} + +/* Dark mode marketing overrides */ +.dark .mkt-logo-chip { + color: rgba(255, 255, 255, 0.3); + border-color: rgba(255, 255, 255, 0.07); + background-color: rgba(255, 255, 255, 0.03); +} +.dark .mkt-logo-chip:hover { + color: rgba(255, 255, 255, 0.8); + border-color: rgba(255, 255, 255, 0.18); + background-color: rgba(255, 255, 255, 0.06); +} + +.dark .mkt-feature-card { + border-color: rgba(255, 255, 255, 0.06); + background-color: rgba(255, 255, 255, 0.02); +} +.dark .mkt-feature-card:hover { + border-color: rgba(249, 115, 22, 0.35); + background-color: rgba(249, 115, 22, 0.06); } \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 976bf62..0064b65 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -4,6 +4,7 @@ import { TRPCReactProvider } from "@/trpc/client"; import { Toaster } from "@/components/ui/sonner"; import { NuqsAdapter } from "nuqs/adapters/next/app"; import { Provider } from "jotai"; +import { SoftwareAppStructuredData, OrganizationStructuredData } from "@/components/structured-data"; import "./globals.css"; import { ThemeProvider } from "@/components/theme-provider"; @@ -19,8 +20,79 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Nodebase", - description: "Nodebase - AI Powered Workflow Automation", + metadataBase: new URL("https://nodebase.tech"), + title: { + default: "Nodebase — Workflow Automation Built for India", + template: "%s | Nodebase", + }, + description: + "Automate your business workflows with India's most powerful automation platform. " + + "Native support for Razorpay, Cashfree, MSG91, Shiprocket, Google Sheets, and 100+ apps. " + + "The n8n and Zapier alternative built for Indian D2C, SaaS, and fintech companies.", + keywords: [ + "workflow automation India", + "n8n alternative India", + "Zapier alternative India", + "business automation India", + "no-code automation India", + "Razorpay automation", + "Cashfree integration", + "D2C automation India", + "SaaS automation India", + "nodebase", + "workflow builder India", + "automation platform India", + "Shiprocket automation", + "MSG91 automation", + "Indian payment automation", + ], + authors: [{ name: "Nodebase" }], + creator: "Nodebase", + publisher: "Nodebase", + robots: { + index: true, + follow: true, + googleBot: { + index: true, + follow: true, + "max-video-preview": -1, + "max-image-preview": "large", + "max-snippet": -1, + }, + }, + openGraph: { + type: "website", + locale: "en_IN", + url: "https://nodebase.tech", + siteName: "Nodebase", + title: "Nodebase — Workflow Automation Built for India", + description: + "Automate your business workflows with India's most powerful automation platform. " + + "Native support for Razorpay, Cashfree, MSG91, Shiprocket, and 100+ apps.", + images: [ + { + url: "./logos/logo.png", + width: 1200, + height: 630, + alt: "Nodebase — Workflow Automation Platform for India", + }, + ], + }, + twitter: { + card: "summary_large_image", + title: "Nodebase — Workflow Automation Built for India", + description: + "The n8n/Zapier alternative for Indian businesses. " + + "Native Razorpay, Cashfree, MSG91 integrations.", + images: ["/opengraph-image"], + creator: "@nodebasetech", + }, + alternates: { + canonical: "https://nodebase.tech", + }, + verification: { + google: process.env.GOOGLE_SITE_VERIFICATION || "", + }, }; export default function RootLayout({ @@ -32,14 +104,15 @@ export default function RootLayout({ + + diff --git a/src/app/opengraph-image.tsx b/src/app/opengraph-image.tsx new file mode 100644 index 0000000..744730d --- /dev/null +++ b/src/app/opengraph-image.tsx @@ -0,0 +1,60 @@ +import { ImageResponse } from "next/og" + +export const runtime = "edge" +export const size = { width: 1200, height: 630 } +export const contentType = "image/png" + +export default async function Image() { + return new ImageResponse( + ( +
+
+ + Nodebase + +
+

+ Workflow Automation +
+ Built for India +

+

+ Razorpay · Cashfree · MSG91 · Shiprocket · 100+ integrations +

+
+ ), + size + ) +} diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 525a917..3302114 100644 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -21,6 +21,7 @@ import { url } from "inspector" import { group } from "console" import { Item } from "@radix-ui/react-accordion" + import { authClient } from "@/lib/auth-client" import { useHasActiveSubscription } from "@/features/auth/components/subscriptions/hooks/use-subscription" @@ -112,13 +113,13 @@ export const AppSidebar = () => { {!hasActiveSubscription && !isLoading && ( authClient.checkout({slug:"pro"})} + onClick={() => router.push("/pricing")} > - Upgrade to Pro + Upgrade Plan @@ -128,13 +129,13 @@ export const AppSidebar = () => { authClient.customer.portal()} + onClick={() => router.push("/pricing")} > - Billing Portal + Billing diff --git a/src/components/entity-components.tsx b/src/components/entity-components.tsx index 8239f57..4c7d82d 100644 --- a/src/components/entity-components.tsx +++ b/src/components/entity-components.tsx @@ -228,7 +228,7 @@ export const EmptyView = ({ onNew }: EmptyViewProps) => { return ( - + diff --git a/src/components/landing/marketing-page.tsx b/src/components/landing/marketing-page.tsx index 3065afc..893cd5d 100644 --- a/src/components/landing/marketing-page.tsx +++ b/src/components/landing/marketing-page.tsx @@ -152,8 +152,8 @@ const PRICING_TIERS = [ price: "₹0", sub: "/month", features: [ - "50 executions/month", - "3 workflows", + "100 workflow runs/month", + "5 workflows", "All nodes included", "Community support", ], @@ -161,30 +161,43 @@ const PRICING_TIERS = [ cta: "Start free", }, { - title: "Pro", + title: "Starter", price: "₹999", sub: "/month", features: [ - "Unlimited executions", + "10,000 workflow runs/month", + "50 workflows", + "Email support", + "All triggers", + ], + featured: false, + cta: "Subscribe Now", + }, + { + title: "Pro", + price: "₹2,499", + sub: "/month", + features: [ + "100,000 workflow runs/month", "Unlimited workflows", "Priority support", - "Custom webhooks", + "API access", ], featured: true, - cta: "Start 14-day trial", + cta: "Go Pro", }, { - title: "Enterprise", - price: "Custom", - sub: "pricing", + title: "Team", + price: "₹5,999", + sub: "/month", features: [ - "Everything in Pro", - "Dedicated instance", + "500,000 workflow runs/month", + "Unlimited workflows", + "Team collaboration", "SLA guarantee", - "Custom nodes", ], featured: false, - cta: "Contact us", + cta: "Contact Sales", }, ]; @@ -957,7 +970,7 @@ function Pricing() {
-
+
{PRICING_TIERS.map((tier, i) => (
+ ) +} + +export function OrganizationStructuredData() { + const data = { + "@context": "https://schema.org", + "@type": "Organization", + "name": "Nodebase", + "url": "https://nodebase.tech", + "logo": "https://nodebase.tech/logos/nodebase.png", + "description": "Workflow automation platform built for Indian businesses.", + "foundingDate": "2025", + "address": { + "@type": "PostalAddress", + "addressCountry": "IN", + "addressRegion": "Rajasthan", + }, + "sameAs": [ + "https://twitter.com/nodebasetech", + "https://github.com/nodebase", + ], + } + + return ( +