diff --git a/.bun-version b/.bun-version index 085c0f2666a..9df886c42a1 100644 --- a/.bun-version +++ b/.bun-version @@ -1 +1 @@ -1.3.14 +1.4.2 diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index e791f3afbdf..5783f9fdee2 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -29,10 +29,17 @@ jobs: uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Setup Bun + id: setup-bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version-file: .bun-version + - name: Cache dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} + - name: Setup Node.js (for native addon compilation) uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: @@ -64,7 +71,7 @@ jobs: run: | set -euo pipefail for attempt in 1 2 3; do - if bun install --frozen; then + if bun install --frozen --ignore-scripts; then exit 0 fi if [ "$attempt" -eq 3 ]; then diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84d8f4d032a..e468802601a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,7 +130,7 @@ jobs: test: name: Test - runs-on: ubuntu-latest + runs-on: blacksmith-8vcpu-ubuntu-2404 steps: - name: Check out code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 @@ -150,12 +150,6 @@ jobs: - name: Install dependencies run: bun install --frozen --ignore-scripts - - name: Test - env: - RELAY_URL: ${{ secrets.RELAY_URL }} - REALTIME_URL: ${{ secrets.REALTIME_URL }} - run: bun run test - # The terminal launch-protection suites (src/terminal/*.node-test.ts) # need real PTYs + node:test, which bun can't provide. - name: Setup Node.js (terminal node-tests) @@ -173,9 +167,11 @@ jobs: (cd "$dir" && ../.bin/prebuild-install) done - - name: Terminal node-tests - working-directory: packages/host-service - run: bun run test:integration:terminal + - name: Test + env: + RELAY_URL: ${{ secrets.RELAY_URL }} + REALTIME_URL: ${{ secrets.REALTIME_URL }} + run: bun x turbo test test:integration:terminal --concurrency=4 page-storage: name: Page storage integration @@ -211,7 +207,7 @@ jobs: typecheck: name: Typecheck - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Check out code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 @@ -234,45 +230,10 @@ jobs: - name: Typecheck run: bun run typecheck - build: - name: Build - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - - - name: Setup Bun - id: setup-bun - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - with: - bun-version-file: .bun-version - - - name: Cache dependencies - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - - name: Install Linux native build deps - run: sudo apt-get update && sudo apt-get install -y libx11-dev libxkbfile-dev - - - name: Install desktop native dependencies - working-directory: apps/desktop - run: bun run install:deps - - - name: Build Desktop - env: - RELAY_URL: ${{ secrets.RELAY_URL }} - REALTIME_URL: ${{ secrets.REALTIME_URL }} - run: bun turbo run build --filter=@superset/desktop - build-cli: name: Build CLI uses: ./.github/workflows/build-cli.yml with: - targets: '[{"os":"ubuntu-latest","target":"linux-x64"},{"os":"macos-14","target":"darwin-arm64"},{"os":"macos-15-intel","target":"darwin-x64"},{"os":"ubuntu-24.04-arm","target":"linux-arm64"}]' + targets: ${{ github.event_name == 'push' && '[{"os":"ubuntu-latest","target":"linux-x64"},{"os":"macos-14","target":"darwin-arm64"},{"os":"macos-15-intel","target":"darwin-x64"},{"os":"ubuntu-24.04-arm","target":"linux-arm64"}]' || '[{"os":"ubuntu-latest","target":"linux-x64"}]' }} upload: false secrets: inherit diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml index 273dcdd8811..3335971a826 100644 --- a/.github/workflows/deploy-preview.yml +++ b/.github/workflows/deploy-preview.yml @@ -3,8 +3,6 @@ name: Deploy Preview on: pull_request: types: [opened, synchronize, reopened] - paths-ignore: - - "apps/desktop/**" concurrency: group: preview-${{ github.event.pull_request.number }} @@ -20,10 +18,41 @@ env: DOCS_ALIAS: docs-pr-${{ github.event.pull_request.number }}-superset.vercel.app jobs: + create-database: + name: Create Database (Neon) + runs-on: ubuntu-latest + environment: preview + + steps: + - name: Create Neon branch + id: create-branch + uses: neondatabase/create-branch-action@fb620d43d4c565abaf088b848a4e28e5c4ea4d9c # 6.3.1 + with: + project_id: ${{ secrets.NEON_PROJECT_ID }} + branch_name: ${{ github.head_ref }} + api_key: ${{ secrets.NEON_API_KEY }} + + - name: Save database connection + run: | + cat > database-status.env << EOF + DATABASE_STATUS="✅" + DATABASE_LINK="View Branch" + DATABASE_URL="${{ steps.create-branch.outputs.db_url_pooled }}" + DATABASE_URL_UNPOOLED="${{ steps.create-branch.outputs.db_url }}" + BRANCH_ID="${{ steps.create-branch.outputs.branch_id }}" + EOF + + - name: Upload database status + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: database-status + path: database-status.env + deploy-database: name: Deploy Database (Neon) runs-on: ubuntu-latest environment: preview + needs: create-database steps: - name: Checkout repository @@ -44,46 +73,28 @@ jobs: - name: Install dependencies run: bun install --frozen --ignore-scripts - - name: Create Neon branch - id: create-branch - uses: neondatabase/create-branch-action@fb620d43d4c565abaf088b848a4e28e5c4ea4d9c # 6.3.1 + - name: Download database info + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: - project_id: ${{ secrets.NEON_PROJECT_ID }} - branch_name: ${{ github.head_ref }} - api_key: ${{ secrets.NEON_API_KEY }} + name: database-status - name: Validate and push database schema working-directory: packages/db env: - DATABASE_URL: ${{ steps.create-branch.outputs.db_url_pooled }} - DATABASE_URL_UNPOOLED: ${{ steps.create-branch.outputs.db_url }} PGOPTIONS: -c lock_timeout=5s -c statement_timeout=60s run: | + set -a + source ../../database-status.env + set +a bun drizzle-kit check bun drizzle-kit migrate bun run src/verify-migrations-applied.ts - - name: Save database success status - run: | - cat > database-status.env << EOF - DATABASE_STATUS="✅" - DATABASE_LINK="View Branch" - DATABASE_URL="${{ steps.create-branch.outputs.db_url_pooled }}" - DATABASE_URL_UNPOOLED="${{ steps.create-branch.outputs.db_url }}" - BRANCH_ID="${{ steps.create-branch.outputs.branch_id }}" - EOF - - - name: Upload database status - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: database-status - path: database-status.env - deploy-api: name: Deploy API - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: preview - needs: deploy-database + needs: create-database steps: - name: Checkout repository @@ -95,6 +106,12 @@ jobs: with: bun-version-file: .bun-version + - name: Cache dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} + - name: Download database info uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: @@ -106,17 +123,16 @@ jobs: echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV echo "DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED" >> $GITHUB_ENV - - name: Cache dependencies - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI - run: npm install --global vercel@$VERCEL_CLI_VERSION + run: bun add --global vercel@$VERCEL_CLI_VERSION + + # Production deploys on main write this cache; a PR only reads it. + - name: Restore Next.js build cache + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: apps/api/.next/cache + key: next-api-${{ github.sha }} + restore-keys: next-api- - name: Build and Deploy API id: deploy @@ -149,7 +165,6 @@ jobs: GH_CLIENT_ID: ${{ secrets.GH_CLIENT_ID }} GH_CLIENT_SECRET: ${{ secrets.GH_CLIENT_SECRET }} NEXT_PUBLIC_SENTRY_DSN_API: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN_API }} - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} NEXT_PUBLIC_SENTRY_ENVIRONMENT: ${{ secrets.NEXT_PUBLIC_SENTRY_ENVIRONMENT }} NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }} NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }} @@ -290,11 +305,11 @@ jobs: deploy-web: name: Deploy Web - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: name: preview url: https://${{ env.WEB_ALIAS }} - needs: deploy-database + needs: create-database steps: - name: Checkout repository @@ -323,11 +338,16 @@ jobs: echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV echo "DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED" >> $GITHUB_ENV - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI - run: npm install --global vercel@$VERCEL_CLI_VERSION + run: bun add --global vercel@$VERCEL_CLI_VERSION + + # Production deploys on main write this cache; a PR only reads it. + - name: Restore Next.js build cache + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: apps/web/.next/cache + key: next-web-${{ github.sha }} + restore-keys: next-web- - name: Build and Deploy Web id: deploy @@ -351,7 +371,6 @@ jobs: NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }} NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }} NEXT_PUBLIC_SENTRY_DSN_WEB: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN_WEB }} - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} NEXT_PUBLIC_SENTRY_ENVIRONMENT: ${{ secrets.NEXT_PUBLIC_SENTRY_ENVIRONMENT }} KV_REST_API_URL: ${{ secrets.KV_REST_API_URL }} KV_REST_API_TOKEN: ${{ secrets.KV_REST_API_TOKEN }} @@ -421,9 +440,9 @@ jobs: deploy-marketing: name: Deploy Marketing - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: preview - needs: deploy-database + needs: create-database steps: - name: Checkout repository @@ -435,6 +454,12 @@ jobs: with: bun-version-file: .bun-version + - name: Cache dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} + - name: Download database info uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: @@ -446,17 +471,16 @@ jobs: echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV echo "DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED" >> $GITHUB_ENV - - name: Cache dependencies - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI - run: npm install --global vercel@$VERCEL_CLI_VERSION + run: bun add --global vercel@$VERCEL_CLI_VERSION + + # Production deploys on main write this cache; a PR only reads it. + - name: Restore Next.js build cache + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: apps/marketing/.next/cache + key: next-marketing-${{ github.sha }} + restore-keys: next-marketing- - name: Build and Deploy Marketing id: deploy @@ -475,7 +499,6 @@ jobs: NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }} NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }} NEXT_PUBLIC_SENTRY_DSN_MARKETING: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN_MARKETING }} - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} NEXT_PUBLIC_SENTRY_ENVIRONMENT: ${{ secrets.NEXT_PUBLIC_SENTRY_ENVIRONMENT }} KV_REST_API_URL: ${{ secrets.KV_REST_API_URL }} KV_REST_API_TOKEN: ${{ secrets.KV_REST_API_TOKEN }} @@ -559,9 +582,9 @@ jobs: deploy-admin: name: Deploy Admin - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: preview - needs: deploy-database + needs: create-database steps: - name: Checkout repository @@ -573,6 +596,12 @@ jobs: with: bun-version-file: .bun-version + - name: Cache dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} + - name: Download database info uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: @@ -584,17 +613,16 @@ jobs: echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV echo "DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED" >> $GITHUB_ENV - - name: Cache dependencies - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI - run: npm install --global vercel@$VERCEL_CLI_VERSION + run: bun add --global vercel@$VERCEL_CLI_VERSION + + # Production deploys on main write this cache; a PR only reads it. + - name: Restore Next.js build cache + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: apps/admin/.next/cache + key: next-admin-${{ github.sha }} + restore-keys: next-admin- - name: Build and Deploy Admin id: deploy @@ -616,7 +644,6 @@ jobs: GOOGLE_SEARCH_CONSOLE_SERVICE_ACCOUNT: ${{ secrets.GOOGLE_SEARCH_CONSOLE_SERVICE_ACCOUNT }} POSTHOG_PROJECT_ID: ${{ secrets.POSTHOG_PROJECT_ID }} NEXT_PUBLIC_SENTRY_DSN_ADMIN: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN_ADMIN }} - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} NEXT_PUBLIC_SENTRY_ENVIRONMENT: ${{ secrets.NEXT_PUBLIC_SENTRY_ENVIRONMENT }} KV_REST_API_URL: ${{ secrets.KV_REST_API_URL }} KV_REST_API_TOKEN: ${{ secrets.KV_REST_API_TOKEN }} @@ -683,9 +710,9 @@ jobs: deploy-docs: name: Deploy Docs - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: preview - needs: deploy-database + needs: create-database steps: - name: Checkout repository @@ -697,6 +724,12 @@ jobs: with: bun-version-file: .bun-version + - name: Cache dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} + - name: Download database info uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: @@ -708,17 +741,8 @@ jobs: echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV echo "DATABASE_URL_UNPOOLED=$DATABASE_URL_UNPOOLED" >> $GITHUB_ENV - - name: Cache dependencies - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI - run: npm install --global vercel@$VERCEL_CLI_VERSION + run: bun add --global vercel@$VERCEL_CLI_VERSION - name: Build and Deploy Docs id: deploy @@ -734,7 +758,6 @@ jobs: NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }} NEXT_PUBLIC_POSTHOG_HOST: ${{ secrets.NEXT_PUBLIC_POSTHOG_HOST }} NEXT_PUBLIC_SENTRY_DSN_DOCS: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN_DOCS }} - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} NEXT_PUBLIC_SENTRY_ENVIRONMENT: ${{ secrets.NEXT_PUBLIC_SENTRY_ENVIRONMENT }} SECRETS_ENCRYPTION_KEY: ${{ secrets.SECRETS_ENCRYPTION_KEY }} run: | @@ -772,7 +795,7 @@ jobs: name: Post Deployment Comment runs-on: ubuntu-latest if: always() - needs: [deploy-database, deploy-api, deploy-web, deploy-marketing, deploy-admin, deploy-docs] + needs: [create-database, deploy-database, deploy-api, deploy-web, deploy-marketing, deploy-admin, deploy-docs] permissions: contents: read pull-requests: write @@ -802,9 +825,12 @@ jobs: DOCS_STATUS="❌" DOCS_LINK="Failed to deploy" - if [[ "${{ needs.deploy-database.result }}" == "success" ]]; then + if [[ "${{ needs.create-database.result }}" == "success" ]]; then source database-status.env fi + if [[ "${{ needs.deploy-database.result }}" != "success" ]]; then + DATABASE_STATUS="❌" + fi if [[ "${{ needs.deploy-api.result }}" == "success" ]]; then source api-status.env diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index a4b7caf82c7..58c1641f661 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -66,7 +66,7 @@ jobs: deploy-api: name: Deploy API to Vercel - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: production needs: deploy-database @@ -86,12 +86,16 @@ jobs: path: ~/.bun/install/cache key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI run: npm install --global vercel@$VERCEL_CLI_VERSION + - name: Cache Next.js build cache + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: apps/api/.next/cache + key: next-api-${{ github.sha }} + restore-keys: next-api- + - name: Build and Deploy API env: VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} @@ -271,7 +275,7 @@ jobs: deploy-web: name: Deploy Web to Vercel - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: production needs: deploy-database @@ -291,12 +295,16 @@ jobs: path: ~/.bun/install/cache key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI run: npm install --global vercel@$VERCEL_CLI_VERSION + - name: Cache Next.js build cache + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: apps/web/.next/cache + key: next-web-${{ github.sha }} + restore-keys: next-web- + - name: Build and Deploy Web env: VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} @@ -369,7 +377,7 @@ jobs: deploy-marketing: name: Deploy Marketing to Vercel - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: production needs: deploy-database @@ -389,12 +397,16 @@ jobs: path: ~/.bun/install/cache key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI run: npm install --global vercel@$VERCEL_CLI_VERSION + - name: Cache Next.js build cache + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: apps/marketing/.next/cache + key: next-marketing-${{ github.sha }} + restore-keys: next-marketing- + - name: Build and Deploy Marketing env: VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} @@ -458,7 +470,7 @@ jobs: deploy-admin: name: Deploy Admin to Vercel - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 environment: production needs: deploy-database @@ -478,12 +490,16 @@ jobs: path: ~/.bun/install/cache key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI run: npm install --global vercel@$VERCEL_CLI_VERSION + - name: Cache Next.js build cache + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: apps/admin/.next/cache + key: next-admin-${{ github.sha }} + restore-keys: next-admin- + - name: Build and Deploy Admin env: VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} @@ -765,9 +781,6 @@ jobs: path: ~/.bun/install/cache key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-revision }}-${{ hashFiles('bun.lock') }} - - name: Install dependencies - run: bun install --frozen --ignore-scripts - - name: Install Vercel CLI run: npm install --global vercel@$VERCEL_CLI_VERSION diff --git a/.github/workflows/sandbox.yml b/.github/workflows/sandbox.yml index 5203d4ac26c..00cc3ce1b0a 100644 --- a/.github/workflows/sandbox.yml +++ b/.github/workflows/sandbox.yml @@ -27,7 +27,7 @@ jobs: boot-twice: name: Boot twice if: github.event_name == 'pull_request' - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Check out code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 @@ -65,6 +65,12 @@ jobs: CDN_URL: ${{ secrets.CDN_URL }} run: bun run build --dry + # Keeps the builder's layers on a persistent disk between runs. + - name: Set up the Docker builder + uses: useblacksmith/setup-docker-builder@19215110ab936351210feebdfa5b440b4493e184 # v2.2.0 + with: + cache-key: sandbox-image + - name: Build the image locally working-directory: packages/sandbox run: bun run image --local diff --git a/AGENTS.md b/AGENTS.md index eb066f8f094..8445c7249a3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -189,6 +189,26 @@ or type it first; a comment is the last resort for what the code genuinely canno constraint that lives outside the repo, or a trap the next reader would walk into. Rationale goes in the commit message and the PR. +## Tests + +CI runs every suite on each push, and the whole run is meant to stay near two minutes. A test +earns its place by catching a regression quickly. + +- **No real waiting.** A test that needs more than bun's default 5 s timeout is too slow. Do not + raise the timeout: pass the delay, clock or retry count in and test with a small value. Never + wait for a real network or process timeout to fire. +- **One test per behaviour.** Stress, fuzz and "adversarial" suites that build many real git + repositories or processes do not go in the repo. When a probe finds a bug, keep the one + regression test for it. +- **Any order, clean checkout.** Suites run with `bun test --isolate`, in an order that differs + between machines, with no root `.env`. Do not `mock.module` a module that other files import for + real (`env`, a client, a logger). Give the code its input instead: a parameter, a placeholder in + the package's test preload, or a local server. +- **A flaky test is a broken test.** Fix the cause or delete it. Do not add retries or longer + timeouts. +- **Node-only suites** (real PTYs, `node:test`) are `*.node-test.ts` files run by a turbo task, so + they run beside the bun suites and not after them. + ## Further reading - `.agents/skills/`: CDP UI verification, mobile simulator verification, DB migrations, tRPC diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index ea958a35144..bd5192c236d 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -6,7 +6,7 @@ This guide is for contributors building Superset from source. If you just want t | Tool | Install | |:-----|:--------| -| [Bun](https://bun.sh/) v1.3.14+ (pinned in `.bun-version`) | `curl -fsSL https://bun.sh/install \| bash` | +| [Bun](https://bun.sh/) v1.4.2+ (pinned in `.bun-version`) | `curl -fsSL https://bun.sh/install \| bash` | | [Docker](https://docs.docker.com/get-docker/) | Docker Desktop or OrbStack | | `jq` | `brew install jq` | | Git 2.20+ and [`gh`](https://cli.github.com/) | `brew install gh` | diff --git a/README.md b/README.md index f732469cce7..267dec28759 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,7 @@ No Neon account or third-party credentials are needed. `setup.local.sh` brings up a local Postgres + neon-proxy + Redis stack via Docker and seeds a dev account. Sign in with the **"Sign in as dev"** button (or `admin@local.test` / `supersetdev`). -Prereqs: [Bun](https://bun.sh/) v1.3.14+ (pinned in `.bun-version`), `docker`, `jq`, and [`gh`](https://cli.github.com/) (`brew install jq gh`). +Prereqs: [Bun](https://bun.sh/) v1.4.2+ (pinned in `.bun-version`), `docker`, `jq`, and [`gh`](https://cli.github.com/) (`brew install jq gh`). See [**DEVELOPMENT.md**](./DEVELOPMENT.md) for the full guide: what the setup script does, manual setup against real services, common commands, troubleshooting, and how to build the desktop app. Contribution process lives in [**CONTRIBUTING.md**](./CONTRIBUTING.md). diff --git a/apps/admin/package.json b/apps/admin/package.json index 4c7e856963b..e333b8fafbe 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -12,8 +12,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@lingui/core": "6.6.0", - "@lingui/react": "6.6.0", + "@lingui/core": "6.8.0", + "@lingui/react": "6.8.0", "@sentry/nextjs": "10.68.0", "@superset/auth": "workspace:*", "@superset/db": "workspace:*", @@ -42,7 +42,7 @@ "require-in-the-middle": "8.0.1", "server-only": "0.0.1", "superjson": "2.2.6", - "zod": "4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@lingui/swc-plugin": "6.6.0", @@ -54,6 +54,6 @@ "babel-plugin-react-compiler": "1.0.0", "dotenv": "17.3.1", "tailwindcss": "4.2.2", - "typescript": "6.0.3" + "typescript": "7.0.2" } } diff --git a/apps/api/package.json b/apps/api/package.json index c1223c11082..30ae89ab6ba 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -8,7 +8,7 @@ "clean": "git clean -xdf .cache .next .turbo node_modules", "dev": "dotenv -e ../../.env -- sh -c 'exec next dev --port ${API_PORT:-3001}'", "start": "next start --port 3001", - "test": "bun test src", + "test": "bun test --isolate src", "typecheck": "tsc --noEmit" }, "dependencies": { @@ -48,7 +48,7 @@ "resend": "6.18.0", "rrule": "2.8.1", "stripe": "20.4.1", - "zod": "4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@lingui/swc-plugin": "6.6.0", @@ -60,6 +60,6 @@ "@types/react-dom": "19.2.3", "babel-plugin-react-compiler": "1.0.0", "dotenv": "17.3.1", - "typescript": "6.0.3" + "typescript": "7.0.2" } } diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 2c1cbe854c2..d2699eb1da9 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -38,7 +38,7 @@ "generate:routes": "tsr generate", "pretypecheck": "bun run generate:icons && bun run generate:routes", "typecheck": "tsc --noEmit", - "test": "bun test" + "test": "bun test --isolate" }, "dependencies": { "@agentclientprotocol/claude-agent-acp": "0.85.0", @@ -76,8 +76,8 @@ "@hookform/resolvers": "5.2.2", "@lezer/highlight": "1.2.3", "@limrun/ui": "0.16.0", - "@lingui/core": "6.6.0", - "@lingui/react": "6.6.0", + "@lingui/core": "6.8.0", + "@lingui/react": "6.8.0", "@novnc/novnc": "1.7.0", "@paper-design/shaders-react": "0.0.77", "@parcel/watcher": "2.5.6", @@ -250,13 +250,13 @@ "utf-8-validate": "6.0.6", "uuid": "14.0.0", "ws": "8.21.3", - "zod": "4.4.3", + "zod": "4.6.5", "zustand": "5.0.12" }, "devDependencies": { "@babel/core": "7.29.7", "@happy-dom/global-registrator": "20.0.2", - "@lingui/babel-plugin-lingui-macro": "6.6.0", + "@lingui/babel-plugin-lingui-macro": "6.8.0", "@sentry/vite-plugin": "5.4.0", "@storybook/react-vite": "10.4.2", "@superset/typescript": "workspace:*", @@ -267,7 +267,7 @@ "@testing-library/react": "16.3.0", "@types/babel__core": "7.20.5", "@types/better-sqlite3": "7.6.13", - "@types/bun": "1.3.14", + "@types/bun": "1.4.2", "@types/culori": "4.0.1", "@types/http-proxy": "1.17.17", "@types/lodash": "4.17.24", @@ -279,6 +279,7 @@ "@types/semver": "7.7.1", "@types/shell-quote": "1.7.5", "@types/ws": "8.18.1", + "@typescript/typescript6": "6.0.2", "@vitejs/plugin-react": "5.2.0", "cross-env": "10.1.0", "electron": "41.10.3", @@ -290,7 +291,7 @@ "storybook": "10.4.2", "tailwindcss": "4.2.2", "tsx": "4.21.0", - "typescript": "6.0.3", + "typescript": "7.0.2", "vite": "7.3.5", "vite-tsconfig-paths": "5.1.4" } diff --git a/apps/desktop/scripts/validate-native-runtime.ts b/apps/desktop/scripts/validate-native-runtime.ts index 59e45feaf9b..f8f08812993 100644 --- a/apps/desktop/scripts/validate-native-runtime.ts +++ b/apps/desktop/scripts/validate-native-runtime.ts @@ -10,7 +10,7 @@ import { existsSync, lstatSync, readdirSync, readFileSync } from "node:fs"; import { builtinModules } from "node:module"; import { join } from "node:path"; -import ts from "typescript"; +import ts from "@typescript/typescript6"; import { mainExternalizedDependencies, requiredMaterializedNodeModules, diff --git a/apps/desktop/src/renderer/components/RendererLayout/renderer-safety.test.ts b/apps/desktop/src/renderer/components/RendererLayout/renderer-safety.test.ts index 0cb4371bfe4..9b3ff9defe1 100644 --- a/apps/desktop/src/renderer/components/RendererLayout/renderer-safety.test.ts +++ b/apps/desktop/src/renderer/components/RendererLayout/renderer-safety.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "bun:test"; import { existsSync, readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; -import ts from "typescript"; +import ts from "@typescript/typescript6"; const renderer = resolve(import.meta.dir, "../.."); diff --git a/apps/desktop/src/renderer/lib/persisted-keys/persisted-keys.test.ts b/apps/desktop/src/renderer/lib/persisted-keys/persisted-keys.test.ts index bcec8800536..4672810df84 100644 --- a/apps/desktop/src/renderer/lib/persisted-keys/persisted-keys.test.ts +++ b/apps/desktop/src/renderer/lib/persisted-keys/persisted-keys.test.ts @@ -8,7 +8,7 @@ import { LanguageVariant, ScriptTarget, SyntaxKind, -} from "typescript"; +} from "@typescript/typescript6"; import { PERSISTED_KEY_REGISTRY } from "./persisted-key-registry.test-data"; import { DEAD_KEYS, sweepDeadPersistedKeys } from "./persisted-keys"; diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useHostReachability/useHostReachability.test.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useHostReachability/useHostReachability.test.ts index afb8cbf999d..f04b24c5544 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useHostReachability/useHostReachability.test.ts +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useHostReachability/useHostReachability.test.ts @@ -10,6 +10,8 @@ const previousWebGlobals = { Event: globalThis.Event, MessageEvent: globalThis.MessageEvent, EventTarget: globalThis.EventTarget, + AbortController: globalThis.AbortController, + AbortSignal: globalThis.AbortSignal, }; const NativeResponse = nativeWebGlobals.Response; const alreadyRegistered = GlobalRegistrator.isRegistered; @@ -31,47 +33,6 @@ afterAll(async () => { Object.assign(globalThis, previousWebGlobals); }); -test("a slow handshake completes while the degraded notice is showing", async () => { - let attempts = 0; - const server = Bun.serve({ - port: 0, - async fetch(request, instance) { - attempts++; - // Longer than the old gate's first forced retry (2s + 5s), - // but within the relay's supported handshake budget. - await Bun.sleep(8_000); - if (instance.upgrade(request)) return; - return new NativeResponse("Upgrade cancelled", { status: 400 }); - }, - websocket: { message() {} }, - }); - const hostUrl = `http://127.0.0.1:${server.port}`; - setHostServiceSecret(hostUrl, "test-token"); - try { - const { result, unmount } = renderHook(() => useHostReachability(hostUrl)); - let sawDegraded = false; - const deadline = Date.now() + 10_000; - while (!result.current.hasConnected && Date.now() < deadline) { - // Flush each transition so the real grace timer and its effects - // run during the handshake, rather than after a single long act. - await act(async () => { - await Bun.sleep(25); - }); - sawDegraded ||= result.current.isDegraded; - } - expect(sawDegraded).toBe(true); - expect(result.current.hasConnected).toBe(true); - expect(result.current.isDegraded).toBe(false); - expect(result.current.isAccessDenied).toBe(false); - expect(attempts).toBe(1); - unmount(); - } finally { - cleanup(); - removeHostServiceSecret(hostUrl); - await server.stop(true); - } -}, 20_000); - test("relay access denial is visible before the notice grace and clears after recovery", async () => { let denied = true; const server = Bun.serve({ diff --git a/apps/desktop/test-setup.ts b/apps/desktop/test-setup.ts index 65378da3a7e..b5c0d470118 100644 --- a/apps/desktop/test-setup.ts +++ b/apps/desktop/test-setup.ts @@ -25,6 +25,8 @@ export const nativeWebGlobals = { Event: globalThis.Event, MessageEvent: globalThis.MessageEvent, EventTarget: globalThis.EventTarget, + AbortController: globalThis.AbortController, + AbortSignal: globalThis.AbortSignal, }; process.env.NODE_ENV = "test"; diff --git a/apps/discord-triage/Dockerfile b/apps/discord-triage/Dockerfile index 1f32253c81a..8c9442fee5c 100644 --- a/apps/discord-triage/Dockerfile +++ b/apps/discord-triage/Dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.3.14 AS base +FROM oven/bun:1.4.2 AS base WORKDIR /app # Stage 1: Prune monorepo to discord-triage's dependency graph diff --git a/apps/discord-triage/package.json b/apps/discord-triage/package.json index 31e092f9904..c376f407b1a 100644 --- a/apps/discord-triage/package.json +++ b/apps/discord-triage/package.json @@ -8,19 +8,19 @@ "start": "bun run src/index.ts", "deploy": "./scripts/deploy.sh", "typecheck": "tsc --noEmit --emitDeclarationOnly false", - "test": "bun test" + "test": "bun test --isolate" }, "dependencies": { "@anthropic-ai/sdk": "0.78.0", "@linear/sdk": "68.1.1", "@t3-oss/env-core": "0.13.11", "discord.js": "14.26.4", - "zod": "4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@superset/typescript": "workspace:*", "@types/node": "24.12.0", - "bun-types": "1.3.14", - "typescript": "6.0.3" + "bun-types": "1.4.2", + "typescript": "7.0.2" } } diff --git a/apps/docs/package.json b/apps/docs/package.json index 4e10e1fa8f0..ca251250be9 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -12,8 +12,8 @@ "postinstall": "fumadocs-mdx" }, "dependencies": { - "@lingui/core": "6.6.0", - "@lingui/react": "6.6.0", + "@lingui/core": "6.8.0", + "@lingui/react": "6.8.0", "@modelcontextprotocol/sdk": "1.30.0", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-scroll-area": "1.2.10", @@ -33,7 +33,7 @@ "react": "19.2.3", "react-dom": "19.2.3", "tailwind-merge": "3.5.0", - "zod": "4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@lingui/swc-plugin": "6.6.0", @@ -46,6 +46,6 @@ "postcss": "8.5.25", "tailwindcss": "4.2.2", "tailwindcss-animate": "1.0.7", - "typescript": "6.0.3" + "typescript": "7.0.2" } } diff --git a/apps/gate/package.json b/apps/gate/package.json index 0d4870ee9bb..e256b4686d0 100644 --- a/apps/gate/package.json +++ b/apps/gate/package.json @@ -11,12 +11,12 @@ "dependencies": { "@superset/shared": "workspace:*", "jose": "6.2.2", - "zod": "4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@cloudflare/workers-types": "5.20260801.1", "@superset/typescript": "workspace:*", - "typescript": "6.0.3", + "typescript": "7.0.2", "wrangler": "4.118.0" } } diff --git a/apps/marketing/next.config.ts b/apps/marketing/next.config.ts index 891bd443b7a..0ac9aa04969 100644 --- a/apps/marketing/next.config.ts +++ b/apps/marketing/next.config.ts @@ -92,6 +92,7 @@ const contentSecurityPolicy = [ const config: NextConfig = { reactStrictMode: true, reactCompiler: true, + cacheComponents: true, typescript: { ignoreBuildErrors: true }, // getInterBold reads the font through process.cwd(), which the tracer @@ -104,6 +105,15 @@ const config: NextConfig = { "/[lang]/user/[handle]/opengraph-image": ["./public/fonts/Inter-Bold.ttf"], }, + // The OG image routes read public/ by a runtime path, so the tracer copies + // all of it into every function. They never read these. + outputFileTracingExcludes: { + "*": [ + "./public/**/*.{mov,mp4,gif}", + "./public/{images,blog,hero,app-icons,media}/**", + ], + }, + // Compiles @lingui/react/macro at build time. Version must stay in // lockstep with Next's swc_core ABI — see plans/20260826-i18n-strategy.md. experimental: { diff --git a/apps/marketing/package.json b/apps/marketing/package.json index 0519ef6700e..12f6f250354 100644 --- a/apps/marketing/package.json +++ b/apps/marketing/package.json @@ -10,12 +10,12 @@ "dev": "dotenv -e ../../.env -- sh -c 'exec next dev --port ${MARKETING_PORT:-3002}'", "lint:prose": "vale --config=vale.ini content \"src/app/[lang]/layout.tsx\" src/components/JsonLd/JsonLd.tsx src/lib/product-facts.ts src/lib/llms.ts \"src/app/[lang]/components/Header/constants.tsx\" \"src/app/[lang]/components/HeroSection/HeroSection.tsx\" \"src/app/[lang]/components/HowItWorksSection\" \"src/app/[lang]/components/FeaturesSection/constants.ts\" \"src/app/[lang]/components/FAQSection/constants.ts\" \"src/app/[lang]/components/CTASection/CTASection.tsx\" \"src/app/[lang]/components/SecuritySection/SecuritySection.tsx\"", "start": "next start", - "test": "bun test", + "test": "bun test --isolate", "typecheck": "tsc --noEmit" }, "dependencies": { - "@lingui/core": "6.6.0", - "@lingui/react": "6.6.0", + "@lingui/core": "6.8.0", + "@lingui/react": "6.8.0", "@paper-design/shaders-react": "0.0.77", "@react-three/drei": "10.7.7", "@react-three/fiber": "9.5.0", @@ -56,7 +56,7 @@ "stripe-gradient": "1.0.1", "superjson": "2.2.6", "three": "0.181.2", - "zod": "4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@lingui/swc-plugin": "6.6.0", @@ -69,9 +69,9 @@ "@types/react-dom": "19.2.3", "@types/three": "0.181.0", "babel-plugin-react-compiler": "1.0.0", - "bun-types": "1.3.14", + "bun-types": "1.4.2", "dotenv": "17.3.1", "tailwindcss": "4.2.2", - "typescript": "6.0.3" + "typescript": "7.0.2" } } diff --git a/apps/marketing/src/app/[lang]/(legal)/[slug]/page.tsx b/apps/marketing/src/app/[lang]/(legal)/[slug]/page.tsx index c505ce5da50..27445be8326 100644 --- a/apps/marketing/src/app/[lang]/(legal)/[slug]/page.tsx +++ b/apps/marketing/src/app/[lang]/(legal)/[slug]/page.tsx @@ -55,8 +55,10 @@ export default async function LegalPage({ params }: PageProps) { ); } -export async function generateStaticParams() { - return getAllLegalSlugs().map((slug) => ({ slug })); +export function generateStaticParams() { + return getAllLegalSlugs() + .slice(0, 1) + .map((slug) => ({ slug })); } export async function generateMetadata({ diff --git a/apps/marketing/src/app/[lang]/blog/[slug]/page.tsx b/apps/marketing/src/app/[lang]/blog/[slug]/page.tsx index d149be17e50..cdeb7fa813a 100644 --- a/apps/marketing/src/app/[lang]/blog/[slug]/page.tsx +++ b/apps/marketing/src/app/[lang]/blog/[slug]/page.tsx @@ -82,8 +82,10 @@ export default async function BlogPostPage({ params }: PageProps) { ); } -export async function generateStaticParams() { - return getAllSlugs().map((slug) => ({ slug })); +export function generateStaticParams() { + return getAllSlugs() + .slice(0, 1) + .map((slug) => ({ slug })); } export async function generateMetadata({ diff --git a/apps/marketing/src/app/[lang]/changelog/[slug]/page.tsx b/apps/marketing/src/app/[lang]/changelog/[slug]/page.tsx index 8c842488841..343fc094333 100644 --- a/apps/marketing/src/app/[lang]/changelog/[slug]/page.tsx +++ b/apps/marketing/src/app/[lang]/changelog/[slug]/page.tsx @@ -5,7 +5,7 @@ import { MDXRemote } from "next-mdx-remote/rsc"; import { localeUrl, localizedAlternates } from "@/app/[lang]/metadata"; import { initServerI18n } from "@/app/i18n-server"; import { ArticleJsonLd, BreadcrumbJsonLd } from "@/components/JsonLd"; -import { getAllChangelogSlugs, getChangelogEntry } from "@/lib/changelog"; +import { getChangelogEntries, getChangelogEntry } from "@/lib/changelog"; import { changelogMdxComponents } from "../components/ChangelogEntry/changelog-mdx-components"; import { ChangelogEntryLayout } from "./components/ChangelogEntryLayout"; @@ -49,8 +49,10 @@ export default async function ChangelogEntryPage({ params }: PageProps) { ); } -export async function generateStaticParams() { - return getAllChangelogSlugs().map((slug) => ({ slug })); +export function generateStaticParams() { + return getChangelogEntries() + .slice(0, 1) + .map((entry) => ({ slug: entry.slug })); } export async function generateMetadata({ diff --git a/apps/marketing/src/app/[lang]/compare/[slug]/page.tsx b/apps/marketing/src/app/[lang]/compare/[slug]/page.tsx index 9a7eb2440ff..285b1fc437b 100644 --- a/apps/marketing/src/app/[lang]/compare/[slug]/page.tsx +++ b/apps/marketing/src/app/[lang]/compare/[slug]/page.tsx @@ -12,7 +12,7 @@ import { FAQPageJsonLd, ItemListJsonLd, } from "@/components/JsonLd"; -import { getAllComparisonSlugs, getComparisonPage } from "@/lib/compare"; +import { getComparisonPage, getComparisonPages } from "@/lib/compare"; import { extractComparisonFaqItems, extractRoundupItems, @@ -83,8 +83,10 @@ export default async function ComparePageRoute({ params }: PageProps) { ); } -export async function generateStaticParams() { - return getAllComparisonSlugs().map((slug) => ({ slug })); +export function generateStaticParams() { + return getComparisonPages() + .slice(0, 1) + .map((page) => ({ slug: page.slug })); } export async function generateMetadata({ diff --git a/apps/marketing/src/app/[lang]/components/CTAButtons/CTAButtons.tsx b/apps/marketing/src/app/[lang]/components/CTAButtons/CTAButtons.tsx index 2b9b6140a32..bc917912c73 100644 --- a/apps/marketing/src/app/[lang]/components/CTAButtons/CTAButtons.tsx +++ b/apps/marketing/src/app/[lang]/components/CTAButtons/CTAButtons.tsx @@ -5,9 +5,10 @@ import { env } from "@/env"; import { HeaderCTA } from "./HeaderCTA"; export async function CTAButtons() { + const requestHeaders = await headers(); let session = null; try { - session = await auth.api.getSession({ headers: await headers() }); + session = await auth.api.getSession({ headers: requestHeaders }); } catch (error) { // Handle errors from invalid/stale cookies (e.g., old Clerk cookies after migration to Better Auth) console.error("[marketing/CTAButtons] Failed to get session:", error); diff --git a/apps/marketing/src/app/[lang]/components/Footer/Footer.tsx b/apps/marketing/src/app/[lang]/components/Footer/Footer.tsx index 3615ed83172..5b93f8cc263 100644 --- a/apps/marketing/src/app/[lang]/components/Footer/Footer.tsx +++ b/apps/marketing/src/app/[lang]/components/Footer/Footer.tsx @@ -163,11 +163,15 @@ const LEGAL_LINKS: FooterLink[] = [ }, ]; -export function Footer({ locale }: { locale?: SupportedLocale }) { +export function Footer({ + locale, + year, +}: { + locale?: SupportedLocale; + year: number; +}) { const isMobileLaunched = useIsMobileLaunched(); const pathname = usePathname(); - // Named local so the copyright message extracts as `{year}`, not `{0}`. - const year = new Date().getFullYear(); if (pathname === "/download") return null; return ( diff --git a/apps/marketing/src/app/[lang]/fight/page.tsx b/apps/marketing/src/app/[lang]/fight/page.tsx index 79ce0d720da..df9f9b359f2 100644 --- a/apps/marketing/src/app/[lang]/fight/page.tsx +++ b/apps/marketing/src/app/[lang]/fight/page.tsx @@ -3,6 +3,7 @@ import { Trans } from "@lingui/react/macro"; import { getI18nInstance } from "@superset/i18n/server"; import { COMPANY } from "@superset/shared/constants"; import type { Metadata } from "next"; +import { cacheLife } from "next/cache"; import { Silkscreen } from "next/font/google"; import { FactoryBackdrop } from "@/app/[lang]/components/FactoryBackdrop"; import { localeUrl, localizedAlternates } from "@/app/[lang]/metadata"; @@ -19,7 +20,7 @@ const pixel = Silkscreen({ display: "swap", }); -export const revalidate = 300; +export const instant = false; interface PageProps { searchParams: Promise<{ a?: string; b?: string }>; @@ -37,6 +38,12 @@ async function resolveMatchup( return [left, right]; } +async function loadParticipant(handle: string) { + "use cache"; + cacheLife({ revalidate: 300 }); + return fetchParticipant(handle, { period: "30d" }); +} + async function resolveFighter(handle?: string): Promise { if (!handle) return null; const normalized = handle.trim().toLowerCase(); @@ -44,7 +51,7 @@ async function resolveFighter(handle?: string): Promise { const house = HOUSE_FIGHTERS.find((entry) => entry.handle === normalized); if (house) return house; - const profile = await fetchParticipant(normalized, { period: "30d" }); + const profile = await loadParticipant(normalized); return profile ? fromParticipant(profile) : null; } diff --git a/apps/marketing/src/app/[lang]/layout.tsx b/apps/marketing/src/app/[lang]/layout.tsx index 4b5ef3418a0..06254f0ad03 100644 --- a/apps/marketing/src/app/[lang]/layout.tsx +++ b/apps/marketing/src/app/[lang]/layout.tsx @@ -1,8 +1,10 @@ -import { getLocaleMessages, SUPPORTED_LOCALES } from "@superset/i18n"; +import { DEFAULT_LOCALE, getLocaleMessages } from "@superset/i18n"; import { COMPANY } from "@superset/shared/constants"; import type { Metadata } from "next"; +import { cacheLife } from "next/cache"; import { IBM_Plex_Mono, Inter } from "next/font/google"; import Script from "next/script"; +import { Suspense } from "react"; import { CookieConsent } from "@/components/CookieConsent"; import { OrganizationJsonLd, @@ -105,11 +107,14 @@ export const metadata: Metadata = { manifest: "/manifest.json", }; -// Declares the locale space for the [lang] segment. Pages themselves stay -// dynamic (the nav resolves the viewer's session), but Next validates and -// types the param set from this. +async function currentYear(): Promise { + "use cache"; + cacheLife("days"); + return new Date().getFullYear(); +} + export function generateStaticParams() { - return SUPPORTED_LOCALES.map((lang) => ({ lang })); + return [{ lang: DEFAULT_LOCALE }]; } export default async function RootLayout({ @@ -157,11 +162,17 @@ export default async function RootLayout({
} + ctaButtons={ + + + + } starCounter={} /> {children} -