From 14aad1157d7d74b5a4600e864e324ae8b78d63ad Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 17 Mar 2026 11:31:28 -0500 Subject: [PATCH 01/47] fix: skills now properly reference origin/canary and create changeset (#2930) --- .claude/skills/release-catalyst/SKILL.md | 2 +- .claude/skills/sync-makeswift/SKILL.md | 3 ++- .gitignore | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.claude/skills/release-catalyst/SKILL.md b/.claude/skills/release-catalyst/SKILL.md index e522ebd33f..3455cab52c 100644 --- a/.claude/skills/release-catalyst/SKILL.md +++ b/.claude/skills/release-catalyst/SKILL.md @@ -58,7 +58,7 @@ Invoke the `/sync-makeswift` skill, with one addition: during the sync (after me **Determine bump type**: Match the bump type from Stage 1 (e.g., if core went `1.4.2` → `1.5.0`, that's a `minor`). -**Create changeset file** (`.changeset/sync-canary-.md`): +**Create changeset file** (`.changeset/sync-canary-.md`, where `` uses hyphens instead of dots — e.g., `1.6.0` → `sync-canary-1-6-0.md`). Changeset filenames only allow lowercase letters and hyphens; dots are invalid. ```markdown --- diff --git a/.claude/skills/sync-makeswift/SKILL.md b/.claude/skills/sync-makeswift/SKILL.md index 83a71522c7..a07c023e3c 100644 --- a/.claude/skills/sync-makeswift/SKILL.md +++ b/.claude/skills/sync-makeswift/SKILL.md @@ -15,7 +15,7 @@ Execute the following phases in order. Pause for user input where indicated. ```bash git fetch origin git checkout -B sync-integrations-makeswift origin/integrations/makeswift -git merge canary +git merge origin/canary ``` If the merge completes cleanly, skip to changeset cleanup. Otherwise, resolve conflicts. @@ -78,5 +78,6 @@ Switch back to `canary` and delete the local branches that are no longer needed: ```bash git checkout canary +git pull git branch -D sync-integrations-makeswift integrations/makeswift ``` diff --git a/.gitignore b/.gitignore index a0caaaaac9..7f7e851692 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ coverage/ .history .unlighthouse .bigcommerce +.mcp.json From 65c6a85f15d36dc8bed3ca89d2fda4ed0463a513 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 17 Mar 2026 15:56:32 -0500 Subject: [PATCH 02/47] chore: audit lighthouse on commits to canary (#2931) --- .../__tests__/audit-unlighthouse.test.mts | 208 ++++++++++++++++++ .../post-unlighthouse-commit-comment.test.mts | 162 ++++++++++++++ ... => post-unlighthouse-pr-comment.test.mts} | 2 +- .github/scripts/audit-unlighthouse.mts | 154 +++++++++++++ .../post-unlighthouse-commit-comment.js | 18 ++ ...ent.js => post-unlighthouse-pr-comment.js} | 0 .github/workflows/regression-tests.yml | 61 ++++- 7 files changed, 601 insertions(+), 4 deletions(-) create mode 100644 .github/scripts/__tests__/audit-unlighthouse.test.mts create mode 100644 .github/scripts/__tests__/post-unlighthouse-commit-comment.test.mts rename .github/scripts/__tests__/{post-unlighthouse-comment.test.mts => post-unlighthouse-pr-comment.test.mts} (99%) create mode 100644 .github/scripts/audit-unlighthouse.mts create mode 100644 .github/scripts/post-unlighthouse-commit-comment.js rename .github/scripts/{post-unlighthouse-comment.js => post-unlighthouse-pr-comment.js} (100%) diff --git a/.github/scripts/__tests__/audit-unlighthouse.test.mts b/.github/scripts/__tests__/audit-unlighthouse.test.mts new file mode 100644 index 0000000000..4d7522c926 --- /dev/null +++ b/.github/scripts/__tests__/audit-unlighthouse.test.mts @@ -0,0 +1,208 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import { buildReport } from '../audit-unlighthouse.mts'; +import type { CiResult } from '../audit-unlighthouse.mts'; + +// --------------------------------------------------------------------------- +// Fixtures +// --------------------------------------------------------------------------- + +const DEFAULT_METRICS: CiResult['summary']['metrics'] = { + 'largest-contentful-paint': { displayValue: '2.5 s' }, + 'cumulative-layout-shift': { displayValue: '0.01' }, + 'first-contentful-paint': { displayValue: '1.2 s' }, + 'total-blocking-time': { displayValue: '100 ms' }, + 'max-potential-fid': { displayValue: '200 ms' }, + interactive: { displayValue: '3.5 s' }, +}; + +function makeCiResult(overrides: { + score?: number; + performance?: number; + accessibility?: number; + 'best-practices'?: number; + seo?: number; + metrics?: CiResult['summary']['metrics']; +} = {}): CiResult { + return { + summary: { + score: overrides.score ?? 0.85, + categories: { + performance: { score: overrides.performance ?? 0.80 }, + accessibility: { score: overrides.accessibility ?? 0.92 }, + 'best-practices': { score: overrides['best-practices'] ?? 1.0 }, + seo: { score: overrides.seo ?? 0.90 }, + }, + metrics: overrides.metrics ?? { ...DEFAULT_METRICS }, + }, + }; +} + +const BASE = makeCiResult(); + +// --------------------------------------------------------------------------- +// Report heading +// --------------------------------------------------------------------------- + +describe('report heading', () => { + it('contains the audit heading', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('## Unlighthouse Audit'), 'Missing main heading'); + }); + + it('appends branch label when branch is given', () => { + const markdown = buildReport(BASE, BASE, 'canary'); + + assert.ok( + markdown.includes('## Unlighthouse Audit — `canary`'), + 'Missing branch label in heading', + ); + }); + + it('handles branch names with slashes', () => { + const markdown = buildReport(BASE, BASE, 'integrations/makeswift'); + + assert.ok(markdown.includes('`integrations/makeswift`')); + }); + + it('omits branch label when none provided', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(!markdown.includes(' — '), 'Should not contain a branch label separator'); + }); + + it('contains the description text', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('Unlighthouse scores for the latest commit on this branch.')); + }); +}); + +// --------------------------------------------------------------------------- +// Summary Score section +// --------------------------------------------------------------------------- + +describe('Summary Score section', () => { + it('contains the Summary Score heading', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('### Summary Score')); + }); + + it('contains the aggregate score note', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('Aggregate score across all categories as reported by Unlighthouse.')); + }); + + it('renders scores as integers on a 1-100 scale', () => { + const desktop = makeCiResult({ score: 0.85 }); + const mobile = makeCiResult({ score: 0.72 }); + const markdown = buildReport(desktop, mobile); + + assert.ok(markdown.includes('| Score | 85 | 72 |')); + }); + + it('rounds fractional scores correctly', () => { + const desktop = makeCiResult({ score: 0.856 }); // rounds to 86 + const markdown = buildReport(desktop, BASE); + + assert.ok(markdown.includes('86'), 'Score 0.856 should round to 86'); + }); + + it('contains the two-column header', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('| | Desktop | Mobile |')); + }); +}); + +// --------------------------------------------------------------------------- +// Category Scores section +// --------------------------------------------------------------------------- + +describe('Category Scores section', () => { + it('contains the Category Scores heading', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('### Category Scores')); + }); + + it('renders all four categories', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('Performance')); + assert.ok(markdown.includes('Accessibility')); + assert.ok(markdown.includes('Best Practices')); + assert.ok(markdown.includes('SEO')); + }); + + it('renders desktop and mobile scores independently', () => { + const desktop = makeCiResult({ performance: 0.80 }); + const mobile = makeCiResult({ performance: 0.93 }); + const markdown = buildReport(desktop, mobile); + + assert.ok( + markdown.includes('| Performance | 80 | 93 |'), + 'Performance row should show desktop then mobile score', + ); + }); + + it('shows all four categories independently', () => { + const desktop = makeCiResult({ seo: 0.88, accessibility: 0.75 }); + const mobile = makeCiResult({ seo: 0.91, accessibility: 0.82 }); + const markdown = buildReport(desktop, mobile); + + assert.ok(markdown.includes('| SEO | 88 | 91 |')); + assert.ok(markdown.includes('| Accessibility | 75 | 82 |')); + }); +}); + +// --------------------------------------------------------------------------- +// Core Web Vitals section +// --------------------------------------------------------------------------- + +describe('Core Web Vitals section', () => { + it('contains the Core Web Vitals heading', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('### Core Web Vitals')); + }); + + it('renders all six metrics', () => { + const markdown = buildReport(BASE, BASE); + + assert.ok(markdown.includes('LCP')); + assert.ok(markdown.includes('CLS')); + assert.ok(markdown.includes('FCP')); + assert.ok(markdown.includes('TBT')); + assert.ok(markdown.includes('Max Potential FID')); + assert.ok(markdown.includes('Time to Interactive')); + }); + + it('passes displayValue through unchanged', () => { + const desktop = makeCiResult({ + metrics: { ...DEFAULT_METRICS, 'largest-contentful-paint': { displayValue: '4.8 s' } }, + }); + const markdown = buildReport(desktop, BASE); + + assert.ok(markdown.includes('4.8 s')); + }); + + it('shows — for a metric missing from a result', () => { + const desktopMissingMetric = makeCiResult({ metrics: {} }); + const markdown = buildReport(desktopMissingMetric, BASE); + + assert.ok(markdown.includes('—'), 'Missing metric should show —'); + }); + + it('shows desktop and mobile displayValues per metric row', () => { + const desktop = makeCiResult({ metrics: { ...DEFAULT_METRICS, 'total-blocking-time': { displayValue: '80 ms' } } }); + const mobile = makeCiResult({ metrics: { ...DEFAULT_METRICS, 'total-blocking-time': { displayValue: '320 ms' } } }); + const markdown = buildReport(desktop, mobile); + + assert.ok(markdown.includes('| TBT | 80 ms | 320 ms |')); + }); +}); diff --git a/.github/scripts/__tests__/post-unlighthouse-commit-comment.test.mts b/.github/scripts/__tests__/post-unlighthouse-commit-comment.test.mts new file mode 100644 index 0000000000..92b6ad4d06 --- /dev/null +++ b/.github/scripts/__tests__/post-unlighthouse-commit-comment.test.mts @@ -0,0 +1,162 @@ +import { describe, it, beforeEach } from 'node:test'; +import assert from 'node:assert/strict'; +import { writeFileSync, mkdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { tmpdir } from 'node:os'; +import { createRequire } from 'node:module'; + +const require = createRequire(import.meta.url); +const postReport = require('../post-unlighthouse-commit-comment.js') as (args: { + github: ReturnType['github']; + context: ReturnType; + reportPath?: string; +}) => Promise; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +interface Calls { + createCommitComment: object[]; +} + +function makeGithub() { + const calls: Calls = { createCommitComment: [] }; + const github = { + rest: { + repos: { + createCommitComment: async (args: object) => { + calls.createCommitComment.push(args); + }, + }, + }, + }; + return { github, calls }; +} + +function makeContext({ + owner = 'test-owner', + repo = 'test-repo', + sha = 'abc123', + runId = 99, +}: { + owner?: string; + repo?: string; + sha?: string; + runId?: number; +} = {}) { + return { + repo: { owner, repo }, + runId, + payload: { + deployment: { sha }, + }, + }; +} + +let reportPath: string; + +beforeEach(() => { + const tmpDir = join(tmpdir(), `post-unlighthouse-report-test-${Date.now()}`); + mkdirSync(tmpDir, { recursive: true }); + reportPath = join(tmpDir, 'report.md'); + writeFileSync(reportPath, '## Unlighthouse Audit — `canary`\n\nSome results.'); +}); + +// --------------------------------------------------------------------------- +// Early exits +// --------------------------------------------------------------------------- + +describe('early exits', () => { + it('does nothing when deployment sha is missing', async () => { + const { github, calls } = makeGithub(); + const context = { ...makeContext(), payload: {} }; + await postReport({ github, context, reportPath }); + + assert.equal(calls.createCommitComment.length, 0); + }); +}); + +// --------------------------------------------------------------------------- +// Commit comment creation +// --------------------------------------------------------------------------- + +describe('commit comment creation', () => { + it('creates a commit comment with the deployment sha', async () => { + const { github, calls } = makeGithub(); + await postReport({ github, context: makeContext({ sha: 'deadbeef' }), reportPath }); + + assert.equal(calls.createCommitComment.length, 1); + assert.equal( + (calls.createCommitComment[0] as { commit_sha: string }).commit_sha, + 'deadbeef', + ); + }); + + it('passes the correct owner and repo', async () => { + const { github, calls } = makeGithub(); + await postReport({ + github, + context: makeContext({ owner: 'my-org', repo: 'my-repo' }), + reportPath, + }); + + assert.equal((calls.createCommitComment[0] as { owner: string }).owner, 'my-org'); + assert.equal((calls.createCommitComment[0] as { repo: string }).repo, 'my-repo'); + }); +}); + +// --------------------------------------------------------------------------- +// Comment body +// --------------------------------------------------------------------------- + +describe('comment body', () => { + it('starts with the canary marker', async () => { + const { github, calls } = makeGithub(); + await postReport({ github, context: makeContext(), reportPath }); + + const body = (calls.createCommitComment[0] as { body: string }).body; + + assert.ok( + body.startsWith('\n'), + `Body should start with marker, got: ${body.slice(0, 60)}`, + ); + }); + + it('includes the report file content', async () => { + const { github, calls } = makeGithub(); + await postReport({ github, context: makeContext(), reportPath }); + + const body = (calls.createCommitComment[0] as { body: string }).body; + + assert.ok(body.includes('## Unlighthouse Audit')); + assert.ok(body.includes('Some results.')); + }); + + it('includes the workflow run link', async () => { + const { github, calls } = makeGithub(); + await postReport({ + github, + context: makeContext({ owner: 'my-org', repo: 'my-repo', runId: 12345 }), + reportPath, + }); + + const body = (calls.createCommitComment[0] as { body: string }).body; + + assert.ok( + body.includes('https://github.com/my-org/my-repo/actions/runs/12345'), + 'Body should contain the workflow run URL', + ); + }); + + it('run link is preceded by a newline', async () => { + const { github, calls } = makeGithub(); + await postReport({ github, context: makeContext(), reportPath }); + + const body = (calls.createCommitComment[0] as { body: string }).body; + const linkIndex = body.indexOf('[Full Unlighthouse report'); + + assert.ok(linkIndex > 0, 'Run link should be present'); + assert.equal(body[linkIndex - 1], '\n', 'Run link should be preceded by a newline'); + }); +}); diff --git a/.github/scripts/__tests__/post-unlighthouse-comment.test.mts b/.github/scripts/__tests__/post-unlighthouse-pr-comment.test.mts similarity index 99% rename from .github/scripts/__tests__/post-unlighthouse-comment.test.mts rename to .github/scripts/__tests__/post-unlighthouse-pr-comment.test.mts index e4b54db698..5f6b3559ab 100644 --- a/.github/scripts/__tests__/post-unlighthouse-comment.test.mts +++ b/.github/scripts/__tests__/post-unlighthouse-pr-comment.test.mts @@ -6,7 +6,7 @@ import { tmpdir } from 'node:os'; import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); -const postComment = require('../post-unlighthouse-comment.js') as (args: { +const postComment = require('../post-unlighthouse-pr-comment.js') as (args: { github: ReturnType['github']; context: ReturnType; provider?: string; diff --git a/.github/scripts/audit-unlighthouse.mts b/.github/scripts/audit-unlighthouse.mts new file mode 100644 index 0000000000..189ed4ab36 --- /dev/null +++ b/.github/scripts/audit-unlighthouse.mts @@ -0,0 +1,154 @@ +#!/usr/bin/env node +/* eslint-disable no-console, no-restricted-syntax, no-plusplus */ + +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { parseArgs } from "node:util"; +import { resolve } from "node:path"; + +interface CiResult { + summary: { + score: number; + categories: Record; + metrics: Record; + }; +} + +function loadCiResult(filePath: string): CiResult { + if (!existsSync(filePath)) { + console.error(`Error: file not found: ${filePath}`); + process.exit(1); + } + + return JSON.parse(readFileSync(filePath, "utf-8")) as CiResult; +} + +function score(value: number): string { + return String(Math.round(value * 100)); +} + +function row(label: string, desktop: string, mobile: string): string { + return `| ${label} | ${desktop} | ${mobile} |`; +} + +const CATEGORY_ORDER = ["performance", "accessibility", "best-practices", "seo"]; + +const CATEGORY_LABELS: Record = { + performance: "Performance", + accessibility: "Accessibility", + "best-practices": "Best Practices", + seo: "SEO", +}; + +const METRIC_ORDER = [ + "largest-contentful-paint", + "cumulative-layout-shift", + "first-contentful-paint", + "total-blocking-time", + "max-potential-fid", + "interactive", +]; + +const METRIC_LABELS: Record = { + "largest-contentful-paint": "LCP", + "cumulative-layout-shift": "CLS", + "first-contentful-paint": "FCP", + "total-blocking-time": "TBT", + "max-potential-fid": "Max Potential FID", + interactive: "Time to Interactive", +}; + +function buildReport( + desktop: CiResult, + mobile: CiResult, + branch?: string, +): string { + const branchLabel = branch ? ` — \`${branch}\`` : ""; + + const lines: string[] = []; + + lines.push(`## Unlighthouse Audit${branchLabel}`); + lines.push("Unlighthouse scores for the latest commit on this branch."); + lines.push(""); + + lines.push("### Summary Score"); + lines.push( + "_Aggregate score across all categories as reported by Unlighthouse._", + ); + lines.push(""); + lines.push("| | Desktop | Mobile |"); + lines.push("|:-|:--------|:-------|"); + lines.push(row("Score", score(desktop.summary.score), score(mobile.summary.score))); + lines.push(""); + + lines.push("### Category Scores"); + lines.push(""); + lines.push("| Category | Desktop | Mobile |"); + lines.push("|:---------|:--------|:-------|"); + + for (const id of CATEGORY_ORDER) { + lines.push( + row( + CATEGORY_LABELS[id] ?? id, + score(desktop.summary.categories[id]?.score ?? 0), + score(mobile.summary.categories[id]?.score ?? 0), + ), + ); + } + + lines.push(""); + + lines.push("### Core Web Vitals"); + lines.push(""); + lines.push("| Metric | Desktop | Mobile |"); + lines.push("|:-------|:--------|:-------|"); + + for (const id of METRIC_ORDER) { + lines.push( + row( + METRIC_LABELS[id] ?? id, + desktop.summary.metrics[id]?.displayValue ?? "—", + mobile.summary.metrics[id]?.displayValue ?? "—", + ), + ); + } + + lines.push(""); + + return lines.join("\n"); +} + +export { buildReport }; +export type { CiResult }; + +const isMain = process.argv[1] === fileURLToPath(import.meta.url); + +if (isMain) { + const { values } = parseArgs({ + options: { + desktop: { type: "string" }, + mobile: { type: "string" }, + branch: { type: "string" }, + output: { type: "string" }, + }, + }); + + if (!values.desktop || !values.mobile) { + console.error( + "Usage: report-unlighthouse.mts --desktop --mobile [--branch ] [--output ]", + ); + process.exit(1); + } + + const desktop = loadCiResult(resolve(values.desktop)); + const mobile = loadCiResult(resolve(values.mobile)); + const markdown = buildReport(desktop, mobile, values.branch); + const outputPath = values.output ? resolve(values.output) : null; + + if (outputPath) { + writeFileSync(outputPath, markdown); + console.error(`Unlighthouse report written to ${outputPath}`); + } else { + process.stdout.write(markdown); + } +} diff --git a/.github/scripts/post-unlighthouse-commit-comment.js b/.github/scripts/post-unlighthouse-commit-comment.js new file mode 100644 index 0000000000..a2a541ead9 --- /dev/null +++ b/.github/scripts/post-unlighthouse-commit-comment.js @@ -0,0 +1,18 @@ +const fs = require('fs'); + +module.exports = async ({ github, context, reportPath = '/tmp/unlighthouse-report.md' }) => { + const sha = context.payload.deployment?.sha; + + if (!sha) return; + + const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + const marker = ``; + const body = marker + '\n' + fs.readFileSync(reportPath, 'utf-8') + `\n[Full Unlighthouse report →](${runUrl})\n`; + + await github.rest.repos.createCommitComment({ + owner: context.repo.owner, + repo: context.repo.repo, + commit_sha: sha, + body, + }); +}; diff --git a/.github/scripts/post-unlighthouse-comment.js b/.github/scripts/post-unlighthouse-pr-comment.js similarity index 100% rename from .github/scripts/post-unlighthouse-comment.js rename to .github/scripts/post-unlighthouse-pr-comment.js diff --git a/.github/workflows/regression-tests.yml b/.github/workflows/regression-tests.yml index 327d7d5b49..cfb49f1e9f 100644 --- a/.github/workflows/regression-tests.yml +++ b/.github/workflows/regression-tests.yml @@ -19,6 +19,8 @@ jobs: provider: ${{ steps.detect.outputs.provider }} is-preview: ${{ steps.detect.outputs.is-preview }} production-url: ${{ steps.detect.outputs.production-url }} + is-canary-branch: ${{ steps.detect.outputs.is-canary-branch }} + branch-label: ${{ steps.detect.outputs.branch-label }} steps: - uses: actions/checkout@v4 @@ -32,6 +34,8 @@ jobs: echo "provider=vercel" >> $GITHUB_OUTPUT if [[ "$ENVIRONMENT" == "Preview" ]]; then echo "is-preview=true" >> $GITHUB_OUTPUT + echo "is-canary-branch=false" >> $GITHUB_OUTPUT + echo "branch-label=" >> $GITHUB_OUTPUT PKG_NAME=$(node -p "require('./core/package.json').name") case "$PKG_NAME" in "@bigcommerce/catalyst-core") @@ -43,12 +47,23 @@ jobs: echo "production-url=" >> $GITHUB_OUTPUT ;; esac else + REF="${{ github.event.deployment.ref }}" echo "is-preview=false" >> $GITHUB_OUTPUT - echo "production-url=" >> $GITHUB_OUTPUT + if [[ "$REF" == "canary" || "$REF" == "integrations/makeswift" ]]; then + echo "is-canary-branch=true" >> $GITHUB_OUTPUT + echo "branch-label=$REF" >> $GITHUB_OUTPUT + echo "production-url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT + else + echo "is-canary-branch=false" >> $GITHUB_OUTPUT + echo "branch-label=" >> $GITHUB_OUTPUT + echo "production-url=" >> $GITHUB_OUTPUT + fi fi elif [[ "$CREATOR" == "cloudflare-pages[bot]" ]]; then echo "provider=cloudflare" >> $GITHUB_OUTPUT + echo "is-canary-branch=false" >> $GITHUB_OUTPUT + echo "branch-label=" >> $GITHUB_OUTPUT if [[ "$ENVIRONMENT" == "Preview" ]]; then echo "is-preview=true" >> $GITHUB_OUTPUT echo "::warning::Cloudflare production URL not yet configured. Skipping comparison." @@ -62,6 +77,8 @@ jobs: echo "::warning::Unknown deployment provider: $CREATOR. Skipping audits." echo "provider=unknown" >> $GITHUB_OUTPUT echo "is-preview=false" >> $GITHUB_OUTPUT + echo "is-canary-branch=false" >> $GITHUB_OUTPUT + echo "branch-label=" >> $GITHUB_OUTPUT echo "production-url=" >> $GITHUB_OUTPUT fi @@ -108,7 +125,7 @@ jobs: unlighthouse-audit-production: name: Unlighthouse Audit Production (${{ needs.detect-provider.outputs.provider }}) - ${{ matrix.device }} needs: [detect-provider] - if: needs.detect-provider.outputs.is-preview == 'true' && needs.detect-provider.outputs.production-url != '' + if: (needs.detect-provider.outputs.is-preview == 'true' && needs.detect-provider.outputs.production-url != '') || needs.detect-provider.outputs.is-canary-branch == 'true' runs-on: ubuntu-latest strategy: matrix: @@ -176,7 +193,7 @@ jobs: uses: actions/github-script@v7 with: script: | - const postComment = require('./.github/scripts/post-unlighthouse-comment.js') + const postComment = require('./.github/scripts/post-unlighthouse-pr-comment.js') await postComment({ github, context, @@ -184,3 +201,41 @@ jobs: reportPath: '/tmp/unlighthouse-report.md', metaPath: '/tmp/unlighthouse-meta.json', }) + + unlighthouse-report: + name: Unlighthouse Report (${{ needs.detect-provider.outputs.provider }}) — ${{ needs.detect-provider.outputs.branch-label }} + needs: [detect-provider, unlighthouse-audit-production] + if: needs.detect-provider.outputs.is-canary-branch == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + + - name: Download production Unlighthouse artifacts + uses: actions/download-artifact@v4 + with: + pattern: unlighthouse-production-*-report + path: /tmp/unlighthouse-artifacts + merge-multiple: false + + - name: Format report + run: | + node .github/scripts/audit-unlighthouse.mts \ + --desktop /tmp/unlighthouse-artifacts/unlighthouse-production-desktop-report/ci-result.json \ + --mobile /tmp/unlighthouse-artifacts/unlighthouse-production-mobile-report/ci-result.json \ + --branch "${{ needs.detect-provider.outputs.branch-label }}" \ + --output /tmp/unlighthouse-report.md + cat /tmp/unlighthouse-report.md >> "$GITHUB_STEP_SUMMARY" + + - name: Post commit comment + uses: actions/github-script@v7 + with: + script: | + const postReport = require('./.github/scripts/post-unlighthouse-commit-comment.js') + await postReport({ github, context, reportPath: '/tmp/unlighthouse-report.md' }) From f3075efde32083603c6790230181f4e01aef76c4 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 17 Mar 2026 17:31:33 -0500 Subject: [PATCH 03/47] fix: use PKG_NAME in regression-tests workflow (#2933) --- .github/workflows/regression-tests.yml | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/regression-tests.yml b/.github/workflows/regression-tests.yml index cfb49f1e9f..ec122b1b91 100644 --- a/.github/workflows/regression-tests.yml +++ b/.github/workflows/regression-tests.yml @@ -47,17 +47,22 @@ jobs: echo "production-url=" >> $GITHUB_OUTPUT ;; esac else - REF="${{ github.event.deployment.ref }}" + PKG_NAME=$(node -p "require('./core/package.json').name") echo "is-preview=false" >> $GITHUB_OUTPUT - if [[ "$REF" == "canary" || "$REF" == "integrations/makeswift" ]]; then - echo "is-canary-branch=true" >> $GITHUB_OUTPUT - echo "branch-label=$REF" >> $GITHUB_OUTPUT - echo "production-url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT - else - echo "is-canary-branch=false" >> $GITHUB_OUTPUT - echo "branch-label=" >> $GITHUB_OUTPUT - echo "production-url=" >> $GITHUB_OUTPUT - fi + case "$PKG_NAME" in + "@bigcommerce/catalyst-core") + echo "is-canary-branch=true" >> $GITHUB_OUTPUT + echo "branch-label=canary" >> $GITHUB_OUTPUT + echo "production-url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT ;; + "@bigcommerce/catalyst-makeswift") + echo "is-canary-branch=true" >> $GITHUB_OUTPUT + echo "branch-label=integrations/makeswift" >> $GITHUB_OUTPUT + echo "production-url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT ;; + *) + echo "is-canary-branch=false" >> $GITHUB_OUTPUT + echo "branch-label=" >> $GITHUB_OUTPUT + echo "production-url=" >> $GITHUB_OUTPUT ;; + esac fi elif [[ "$CREATOR" == "cloudflare-pages[bot]" ]]; then From 6a5b019083aa3e000e5989f6f13256b57c22c479 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Thu, 19 Mar 2026 12:08:39 -0600 Subject: [PATCH 04/47] CATALYST-1570: fix(ui) - Reduce dropdown menu border width to match select (#2934) The dropdown menu used `ring` (3px default) while the Select component used `ring-1` (1px). This caused a visually thick border on dropdown menus, most noticeably on the wishlist page. Fixes CATALYST-1570 Co-authored-by: Claude --- .changeset/fix-dropdown-menu-border.md | 5 +++++ core/vibes/soul/primitives/dropdown-menu/index.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-dropdown-menu-border.md diff --git a/.changeset/fix-dropdown-menu-border.md b/.changeset/fix-dropdown-menu-border.md new file mode 100644 index 0000000000..baf086d7f2 --- /dev/null +++ b/.changeset/fix-dropdown-menu-border.md @@ -0,0 +1,5 @@ +--- +'@bigcommerce/catalyst-core': patch +--- + +Fix extra thick border on dropdown menu by changing `ring` (3px) to `ring-1` (1px) to match the Select component styling. diff --git a/core/vibes/soul/primitives/dropdown-menu/index.tsx b/core/vibes/soul/primitives/dropdown-menu/index.tsx index 3089825aec..f9dd60d723 100644 --- a/core/vibes/soul/primitives/dropdown-menu/index.tsx +++ b/core/vibes/soul/primitives/dropdown-menu/index.tsx @@ -62,7 +62,7 @@ export const DropdownMenu = ({ Date: Thu, 19 Mar 2026 13:27:51 -0500 Subject: [PATCH 05/47] Update required version of Node in README.md (#2936) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 029d02b723..1dd8389dff 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Check out the [Catalyst.dev One-Click Catalyst Documentation](https://www.cataly **Requirements:** - A [BigCommerce account](https://www.bigcommerce.com/start-your-trial) -- Node.js version 20 or 22 +- Node.js version 24 - Corepack-enabled `pnpm` ```bash From 59873b1f53d728f4c4e6bb5d283804f9cb8ac778 Mon Sep 17 00:00:00 2001 From: BigEth4n <101482036+BigEth4n@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:49:05 -0500 Subject: [PATCH 06/47] Update One-Click Catalyst flow to specify Node v24 (#2937) Updated the required Node.js versions to only allow version 24. --- packages/create-catalyst/bin/index.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-catalyst/bin/index.cjs b/packages/create-catalyst/bin/index.cjs index 5792450ddd..6d5466ad2a 100644 --- a/packages/create-catalyst/bin/index.cjs +++ b/packages/create-catalyst/bin/index.cjs @@ -6,7 +6,7 @@ const semver = require('semver'); * Discourage use of odd-numbered versions of Node.js * @see https://nodejs.org/en/about/previous-releases#nodejs-releases */ -const catalystRequiredNodeVersions = ['^20', '^22']; +const catalystRequiredNodeVersions = ['^24']; const userNodeVersion = process.version; if (!catalystRequiredNodeVersions.some((version) => semver.satisfies(userNodeVersion, version))) { From a4b614d99a208f21b4d4ee1462666581f21335d8 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:19:47 -0600 Subject: [PATCH 07/47] fix: require Node.js v24 for create-catalyst, align engine constraints (#2940) * Initial plan * fix: align Node.js v24 engine requirements across create-catalyst and core - Update packages/create-catalyst/package.json engines from ^20.0.0 || ^22.0.0 || ^24.0.0 to ^24.0.0 to match the runtime check in bin/index.cjs and core/package.json (>=24.0.0) - Fix core/README.md which referenced Node.js version 20 or 22 instead of 24 - Extract supported Node.js versions into bin/supported-node-versions.cjs as the single source of truth - Add src/utils/node-version.spec.ts to test the version gating logic Closes #2939 Co-authored-by: chanceaclark <10539418+chanceaclark@users.noreply.github.com> * fix: resolve lint errors in node-version.spec.ts - Use named import { satisfies } from 'semver' instead of default import (fixes import/no-named-as-default-member warning) - Remove require() of .cjs file to avoid import/extensions and @typescript-eslint/consistent-type-assertions errors - Simplify bin/index.cjs to remove unused intermediate variable Co-authored-by: chanceaclark <10539418+chanceaclark@users.noreply.github.com> * chore: add changeset for Node.js v24 engine alignment in create-catalyst Co-authored-by: chanceaclark <10539418+chanceaclark@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: chanceaclark <10539418+chanceaclark@users.noreply.github.com> --- .changeset/fix-create-catalyst-node-v24.md | 5 +++ core/README.md | 2 +- packages/create-catalyst/bin/index.cjs | 7 ++-- .../bin/supported-node-versions.cjs | 8 +++++ packages/create-catalyst/package.json | 2 +- .../src/utils/node-version.spec.ts | 32 +++++++++++++++++++ 6 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 .changeset/fix-create-catalyst-node-v24.md create mode 100644 packages/create-catalyst/bin/supported-node-versions.cjs create mode 100644 packages/create-catalyst/src/utils/node-version.spec.ts diff --git a/.changeset/fix-create-catalyst-node-v24.md b/.changeset/fix-create-catalyst-node-v24.md new file mode 100644 index 0000000000..8dc1bfa005 --- /dev/null +++ b/.changeset/fix-create-catalyst-node-v24.md @@ -0,0 +1,5 @@ +--- +'@bigcommerce/create-catalyst': patch +--- + +Align Node.js engine requirement with v24. The `engines.node` field in `create-catalyst` now matches the runtime version gate (`^24.0.0`), ensuring `pnpm create @bigcommerce/catalyst` correctly rejects unsupported Node versions before installation begins. diff --git a/core/README.md b/core/README.md index 6ce5bf2343..10ded1d1c3 100644 --- a/core/README.md +++ b/core/README.md @@ -47,7 +47,7 @@ Check out the [Catalyst.dev One-Click Catalyst Documentation](https://www.cataly **Requirements:** - A [BigCommerce account](https://www.bigcommerce.com/start-your-trial) -- Node.js version 20 or 22 +- Node.js version 24 - Corepack-enabled `pnpm` ```bash diff --git a/packages/create-catalyst/bin/index.cjs b/packages/create-catalyst/bin/index.cjs index 6d5466ad2a..160f41ee52 100644 --- a/packages/create-catalyst/bin/index.cjs +++ b/packages/create-catalyst/bin/index.cjs @@ -1,12 +1,9 @@ #!/usr/bin/env node const semver = require('semver'); +const { CATALYST_REQUIRED_NODE_VERSIONS } = require('./supported-node-versions.cjs'); -/** - * Discourage use of odd-numbered versions of Node.js - * @see https://nodejs.org/en/about/previous-releases#nodejs-releases - */ -const catalystRequiredNodeVersions = ['^24']; +const catalystRequiredNodeVersions = CATALYST_REQUIRED_NODE_VERSIONS; const userNodeVersion = process.version; if (!catalystRequiredNodeVersions.some((version) => semver.satisfies(userNodeVersion, version))) { diff --git a/packages/create-catalyst/bin/supported-node-versions.cjs b/packages/create-catalyst/bin/supported-node-versions.cjs new file mode 100644 index 0000000000..074937a5c5 --- /dev/null +++ b/packages/create-catalyst/bin/supported-node-versions.cjs @@ -0,0 +1,8 @@ +/** + * Supported Node.js version ranges for Catalyst. + * Odd-numbered versions are discouraged per the Node.js release policy. + * @see https://nodejs.org/en/about/previous-releases#nodejs-releases + */ +const CATALYST_REQUIRED_NODE_VERSIONS = ['^24']; + +module.exports = { CATALYST_REQUIRED_NODE_VERSIONS }; diff --git a/packages/create-catalyst/package.json b/packages/create-catalyst/package.json index e1f1c1265d..a11b74ae7a 100644 --- a/packages/create-catalyst/package.json +++ b/packages/create-catalyst/package.json @@ -15,7 +15,7 @@ "build": "tsup" }, "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" + "node": "^24.0.0" }, "dependencies": { "@commander-js/extra-typings": "^14.0.0", diff --git a/packages/create-catalyst/src/utils/node-version.spec.ts b/packages/create-catalyst/src/utils/node-version.spec.ts new file mode 100644 index 0000000000..e6020ea07c --- /dev/null +++ b/packages/create-catalyst/src/utils/node-version.spec.ts @@ -0,0 +1,32 @@ +import { satisfies } from 'semver'; + +const REQUIRED_NODE_VERSIONS = ['^24']; + +const isNodeVersionSupported = (version: string) => + REQUIRED_NODE_VERSIONS.some((range) => satisfies(version, range)); + +describe('Node.js version gating (mirrors bin/index.cjs)', () => { + it('accepts the minimum supported version (24.0.0)', () => { + expect(isNodeVersionSupported('24.0.0')).toBe(true); + }); + + it('accepts a recent Node v24 release', () => { + expect(isNodeVersionSupported('24.1.0')).toBe(true); + }); + + it('rejects Node v20', () => { + expect(isNodeVersionSupported('20.0.0')).toBe(false); + }); + + it('rejects Node v22', () => { + expect(isNodeVersionSupported('22.0.0')).toBe(false); + }); + + it('rejects older Node v18', () => { + expect(isNodeVersionSupported('18.0.0')).toBe(false); + }); + + it('rejects odd-numbered Node v23', () => { + expect(isNodeVersionSupported('23.0.0')).toBe(false); + }); +}); From cba98e3e1ea33f203da1779ec623b0a277c40023 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:34:28 -0600 Subject: [PATCH 08/47] Version Packages (`canary`) (#2935) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/fix-create-catalyst-node-v24.md | 5 ----- .changeset/fix-dropdown-menu-border.md | 5 ----- core/CHANGELOG.md | 6 ++++++ core/package.json | 2 +- packages/create-catalyst/CHANGELOG.md | 6 ++++++ packages/create-catalyst/package.json | 2 +- 6 files changed, 14 insertions(+), 12 deletions(-) delete mode 100644 .changeset/fix-create-catalyst-node-v24.md delete mode 100644 .changeset/fix-dropdown-menu-border.md diff --git a/.changeset/fix-create-catalyst-node-v24.md b/.changeset/fix-create-catalyst-node-v24.md deleted file mode 100644 index 8dc1bfa005..0000000000 --- a/.changeset/fix-create-catalyst-node-v24.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@bigcommerce/create-catalyst': patch ---- - -Align Node.js engine requirement with v24. The `engines.node` field in `create-catalyst` now matches the runtime version gate (`^24.0.0`), ensuring `pnpm create @bigcommerce/catalyst` correctly rejects unsupported Node versions before installation begins. diff --git a/.changeset/fix-dropdown-menu-border.md b/.changeset/fix-dropdown-menu-border.md deleted file mode 100644 index baf086d7f2..0000000000 --- a/.changeset/fix-dropdown-menu-border.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@bigcommerce/catalyst-core': patch ---- - -Fix extra thick border on dropdown menu by changing `ring` (3px) to `ring-1` (1px) to match the Select component styling. diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index a19a62de7c..c15a19559e 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.6.1 + +### Patch Changes + +- [#2934](https://github.com/bigcommerce/catalyst/pull/2934) [`6a5b019`](https://github.com/bigcommerce/catalyst/commit/6a5b019083aa3e000e5989f6f13256b57c22c479) Thanks [@chanceaclark](https://github.com/chanceaclark)! - Fix extra thick border on dropdown menu by changing `ring` (3px) to `ring-1` (1px) to match the Select component styling. + ## 1.6.0 ### Minor Changes diff --git a/core/package.json b/core/package.json index 2dd2e00aa6..2a4fd29e81 100644 --- a/core/package.json +++ b/core/package.json @@ -1,7 +1,7 @@ { "name": "@bigcommerce/catalyst-core", "description": "BigCommerce Catalyst is a Next.js starter kit for building headless BigCommerce storefronts.", - "version": "1.6.0", + "version": "1.6.1", "private": true, "engines": { "node": ">=24.0.0" diff --git a/packages/create-catalyst/CHANGELOG.md b/packages/create-catalyst/CHANGELOG.md index 0e9d804c9c..41935d1509 100644 --- a/packages/create-catalyst/CHANGELOG.md +++ b/packages/create-catalyst/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.2 + +### Patch Changes + +- [#2940](https://github.com/bigcommerce/catalyst/pull/2940) [`a4b614d`](https://github.com/bigcommerce/catalyst/commit/a4b614d99a208f21b4d4ee1462666581f21335d8) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Align Node.js engine requirement with v24. The `engines.node` field in `create-catalyst` now matches the runtime version gate (`^24.0.0`), ensuring `pnpm create @bigcommerce/catalyst` correctly rejects unsupported Node versions before installation begins. + ## 1.0.1 ### Patch Changes diff --git a/packages/create-catalyst/package.json b/packages/create-catalyst/package.json index a11b74ae7a..2969b5f504 100644 --- a/packages/create-catalyst/package.json +++ b/packages/create-catalyst/package.json @@ -1,6 +1,6 @@ { "name": "@bigcommerce/create-catalyst", - "version": "1.0.1", + "version": "1.0.2", "type": "module", "bin": "bin/index.cjs", "files": [ From c965f4d69e1fb38ea7b2f4f3ae30dae5e2064453 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Fri, 20 Mar 2026 12:50:55 -0600 Subject: [PATCH 09/47] fix: add repository field to published packages (#2941) npm's sigstore provenance verification requires package.json to have a repository.url matching the GitHub repository. Without this field, changeset publish fails with E422 for all published packages. Co-authored-by: Claude --- packages/client/package.json | 5 +++++ packages/create-catalyst/package.json | 5 +++++ packages/eslint-config-catalyst/package.json | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/packages/client/package.json b/packages/client/package.json index c8081b156f..f201af1b45 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -2,6 +2,11 @@ "name": "@bigcommerce/catalyst-client", "description": "BigCommerce API client for Catalyst.", "version": "1.0.1", + "repository": { + "type": "git", + "url": "https://github.com/bigcommerce/catalyst", + "directory": "packages/client" + }, "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { diff --git a/packages/create-catalyst/package.json b/packages/create-catalyst/package.json index 2969b5f504..e7156dbb8f 100644 --- a/packages/create-catalyst/package.json +++ b/packages/create-catalyst/package.json @@ -1,6 +1,11 @@ { "name": "@bigcommerce/create-catalyst", "version": "1.0.2", + "repository": { + "type": "git", + "url": "https://github.com/bigcommerce/catalyst", + "directory": "packages/create-catalyst" + }, "type": "module", "bin": "bin/index.cjs", "files": [ diff --git a/packages/eslint-config-catalyst/package.json b/packages/eslint-config-catalyst/package.json index a1800b0b3b..bc4f98b04e 100644 --- a/packages/eslint-config-catalyst/package.json +++ b/packages/eslint-config-catalyst/package.json @@ -2,6 +2,11 @@ "name": "@bigcommerce/eslint-config-catalyst", "description": "Eslint configs for catalyst", "version": "1.0.0", + "repository": { + "type": "git", + "url": "https://github.com/bigcommerce/catalyst", + "directory": "packages/eslint-config-catalyst" + }, "files": [ "./base.js", "./next.js", From 91d8da7a30afe6fe2e6d8aca41bcb2d061ecf048 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 13:29:24 -0600 Subject: [PATCH 10/47] Version Packages (`integrations/makeswift`) (#2943) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/sync-canary-1-6-1.md | 5 ----- core/CHANGELOG.md | 6 ++++++ core/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/sync-canary-1-6-1.md diff --git a/.changeset/sync-canary-1-6-1.md b/.changeset/sync-canary-1-6-1.md deleted file mode 100644 index 03a022b935..0000000000 --- a/.changeset/sync-canary-1-6-1.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bigcommerce/catalyst-makeswift": patch ---- - -Pulls in changes from the `@bigcommerce/catalyst-core@1.6.1` release. For more information about what was included in the `@bigcommerce/catalyst-core@1.6.1` release, see the [changelog entry](https://github.com/bigcommerce/catalyst/blob/cba98e3e1ea33f203da1779ec623b0a277c40023/core/CHANGELOG.md#161). diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 395b8d3930..128696e1ce 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.6.2 + +### Patch Changes + +- Pulls in changes from the `@bigcommerce/catalyst-core@1.6.1` release. For more information about what was included in the `@bigcommerce/catalyst-core@1.6.1` release, see the [changelog entry](https://github.com/bigcommerce/catalyst/blob/cba98e3e1ea33f203da1779ec623b0a277c40023/core/CHANGELOG.md#161). + ## 1.6.1 ### Patch Changes diff --git a/core/package.json b/core/package.json index 6d79eaa9d0..bc97ba687d 100644 --- a/core/package.json +++ b/core/package.json @@ -1,7 +1,7 @@ { "name": "@bigcommerce/catalyst-makeswift", "description": "BigCommerce Catalyst is a Next.js starter kit for building headless BigCommerce storefronts.", - "version": "1.6.1", + "version": "1.6.2", "private": true, "engines": { "node": ">=24.0.0" From 447996400e6fcc6388937011e101d802308e6b33 Mon Sep 17 00:00:00 2001 From: bc-svc-local <102379007+bc-svc-local@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:28:12 +0100 Subject: [PATCH 11/47] Update translations (#2945) * feat(other): LOCAL-1444 delivery translation * chore(core): create translations patch --------- Co-authored-by: bc-svc-local --- .changeset/translations-patch-5c63d5bb.md | 5 +++++ core/messages/da.json | 8 ++++---- core/messages/de.json | 8 ++++---- core/messages/es-419.json | 8 ++++---- core/messages/es-AR.json | 8 ++++---- core/messages/es-CL.json | 8 ++++---- core/messages/es-CO.json | 8 ++++---- core/messages/es-LA.json | 8 ++++---- core/messages/es-MX.json | 8 ++++---- core/messages/es-PE.json | 8 ++++---- core/messages/es.json | 8 ++++---- core/messages/fr.json | 8 ++++---- core/messages/it.json | 8 ++++---- core/messages/ja.json | 8 ++++---- core/messages/nl.json | 8 ++++---- core/messages/no.json | 8 ++++---- core/messages/sv.json | 8 ++++---- 17 files changed, 69 insertions(+), 64 deletions(-) create mode 100644 .changeset/translations-patch-5c63d5bb.md diff --git a/.changeset/translations-patch-5c63d5bb.md b/.changeset/translations-patch-5c63d5bb.md new file mode 100644 index 0000000000..ad17b2636a --- /dev/null +++ b/.changeset/translations-patch-5c63d5bb.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Update translations. diff --git a/core/messages/da.json b/core/messages/da.json index 8ebd11ce03..1bb6967bfc 100644 --- a/core/messages/da.json +++ b/core/messages/da.json @@ -98,7 +98,7 @@ "heading": "Ny konto", "cta": "Opret konto", "somethingWentWrong": "Noget gik galt. Prøv igen senere.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Udfyld reCAPTCHA-bekræftelsen.", "FieldErrors": { "firstNameRequired": "Fornavnet er påkrævet", "lastNameRequired": "Efternavnet er påkrævet", @@ -506,7 +506,7 @@ "emailLabel": "E-mail", "successMessage": "Din anmeldelse er blevet indsendt!", "somethingWentWrong": "Noget gik galt. Prøv igen senere.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Udfyld reCAPTCHA-bekræftelsen.", "FieldErrors": { "titleRequired": "Titel er påkrævet", "authorRequired": "Navn er påkrævet", @@ -538,7 +538,7 @@ "comments": "Kommentarer/spørgsmål", "cta": "Indsend formular", "somethingWentWrong": "Noget gik galt. Prøv igen senere.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Udfyld reCAPTCHA-bekræftelsen." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Valgfrit", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Udfyld reCAPTCHA-bekræftelsen.", "Errors": { "invalidInput": "Tjek din indtastning, og prøv igen", "invalidFormat": "Den indtastede værdi stemmer ikke overens med det krævede format" diff --git a/core/messages/de.json b/core/messages/de.json index 0a1e261336..56596f4fc8 100644 --- a/core/messages/de.json +++ b/core/messages/de.json @@ -98,7 +98,7 @@ "heading": "Neues Konto", "cta": "Konto erstellen", "somethingWentWrong": "Es ist etwas schiefgegangen Bitte versuchen Sie es später erneut.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Bitte führen Sie die reCAPTCHA-Verifizierung durch.", "FieldErrors": { "firstNameRequired": "Es muss ein Vorname angegeben werden", "lastNameRequired": "Es muss ein Nachname angegeben werden", @@ -506,7 +506,7 @@ "emailLabel": "E-Mail", "successMessage": "Ihre Bewertung wurde erfolgreich übermittelt!", "somethingWentWrong": "Es ist etwas schiefgegangen Bitte versuchen Sie es später erneut.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Bitte führen Sie die reCAPTCHA-Verifizierung durch.", "FieldErrors": { "titleRequired": "Titel ist erforderlich", "authorRequired": "Es muss ein Name angegeben werden", @@ -538,7 +538,7 @@ "comments": "Kommentare/Fragen", "cta": "Formular einreichen", "somethingWentWrong": "Es ist etwas schiefgegangen Bitte versuchen Sie es später erneut.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Bitte führen Sie die reCAPTCHA-Verifizierung durch." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "optional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Bitte führen Sie die reCAPTCHA-Verifizierung durch.", "Errors": { "invalidInput": "Bitte überprüfen Sie Ihre Eingabe und versuchen Sie es erneut", "invalidFormat": "Der eingegebene Wert entspricht nicht dem erforderlichen Format" diff --git a/core/messages/es-419.json b/core/messages/es-419.json index 65c6b149e7..f5e29ab304 100644 --- a/core/messages/es-419.json +++ b/core/messages/es-419.json @@ -98,7 +98,7 @@ "heading": "Cuenta nueva", "cta": "Crear cuenta", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "firstNameRequired": "El campo Nombre es obligatorio.", "lastNameRequired": "El campo Apellido es obligatorio.", @@ -506,7 +506,7 @@ "emailLabel": "Correo electrónico", "successMessage": "¡Tu reseña fue enviada con éxito!", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "titleRequired": "Se requiere título", "authorRequired": "El campo Nombre es obligatorio", @@ -538,7 +538,7 @@ "comments": "Comentarios/Preguntas", "cta": "Enviar formulario", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Opcional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "Errors": { "invalidInput": "Por favor, revisa tu opinión y vuelve a intentarlo", "invalidFormat": "El valor introducido no coincide con el formato requerido" diff --git a/core/messages/es-AR.json b/core/messages/es-AR.json index 65c6b149e7..f5e29ab304 100644 --- a/core/messages/es-AR.json +++ b/core/messages/es-AR.json @@ -98,7 +98,7 @@ "heading": "Cuenta nueva", "cta": "Crear cuenta", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "firstNameRequired": "El campo Nombre es obligatorio.", "lastNameRequired": "El campo Apellido es obligatorio.", @@ -506,7 +506,7 @@ "emailLabel": "Correo electrónico", "successMessage": "¡Tu reseña fue enviada con éxito!", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "titleRequired": "Se requiere título", "authorRequired": "El campo Nombre es obligatorio", @@ -538,7 +538,7 @@ "comments": "Comentarios/Preguntas", "cta": "Enviar formulario", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Opcional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "Errors": { "invalidInput": "Por favor, revisa tu opinión y vuelve a intentarlo", "invalidFormat": "El valor introducido no coincide con el formato requerido" diff --git a/core/messages/es-CL.json b/core/messages/es-CL.json index 65c6b149e7..f5e29ab304 100644 --- a/core/messages/es-CL.json +++ b/core/messages/es-CL.json @@ -98,7 +98,7 @@ "heading": "Cuenta nueva", "cta": "Crear cuenta", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "firstNameRequired": "El campo Nombre es obligatorio.", "lastNameRequired": "El campo Apellido es obligatorio.", @@ -506,7 +506,7 @@ "emailLabel": "Correo electrónico", "successMessage": "¡Tu reseña fue enviada con éxito!", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "titleRequired": "Se requiere título", "authorRequired": "El campo Nombre es obligatorio", @@ -538,7 +538,7 @@ "comments": "Comentarios/Preguntas", "cta": "Enviar formulario", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Opcional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "Errors": { "invalidInput": "Por favor, revisa tu opinión y vuelve a intentarlo", "invalidFormat": "El valor introducido no coincide con el formato requerido" diff --git a/core/messages/es-CO.json b/core/messages/es-CO.json index 65c6b149e7..f5e29ab304 100644 --- a/core/messages/es-CO.json +++ b/core/messages/es-CO.json @@ -98,7 +98,7 @@ "heading": "Cuenta nueva", "cta": "Crear cuenta", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "firstNameRequired": "El campo Nombre es obligatorio.", "lastNameRequired": "El campo Apellido es obligatorio.", @@ -506,7 +506,7 @@ "emailLabel": "Correo electrónico", "successMessage": "¡Tu reseña fue enviada con éxito!", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "titleRequired": "Se requiere título", "authorRequired": "El campo Nombre es obligatorio", @@ -538,7 +538,7 @@ "comments": "Comentarios/Preguntas", "cta": "Enviar formulario", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Opcional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "Errors": { "invalidInput": "Por favor, revisa tu opinión y vuelve a intentarlo", "invalidFormat": "El valor introducido no coincide con el formato requerido" diff --git a/core/messages/es-LA.json b/core/messages/es-LA.json index 65c6b149e7..f5e29ab304 100644 --- a/core/messages/es-LA.json +++ b/core/messages/es-LA.json @@ -98,7 +98,7 @@ "heading": "Cuenta nueva", "cta": "Crear cuenta", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "firstNameRequired": "El campo Nombre es obligatorio.", "lastNameRequired": "El campo Apellido es obligatorio.", @@ -506,7 +506,7 @@ "emailLabel": "Correo electrónico", "successMessage": "¡Tu reseña fue enviada con éxito!", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "titleRequired": "Se requiere título", "authorRequired": "El campo Nombre es obligatorio", @@ -538,7 +538,7 @@ "comments": "Comentarios/Preguntas", "cta": "Enviar formulario", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Opcional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "Errors": { "invalidInput": "Por favor, revisa tu opinión y vuelve a intentarlo", "invalidFormat": "El valor introducido no coincide con el formato requerido" diff --git a/core/messages/es-MX.json b/core/messages/es-MX.json index 65c6b149e7..f5e29ab304 100644 --- a/core/messages/es-MX.json +++ b/core/messages/es-MX.json @@ -98,7 +98,7 @@ "heading": "Cuenta nueva", "cta": "Crear cuenta", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "firstNameRequired": "El campo Nombre es obligatorio.", "lastNameRequired": "El campo Apellido es obligatorio.", @@ -506,7 +506,7 @@ "emailLabel": "Correo electrónico", "successMessage": "¡Tu reseña fue enviada con éxito!", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "titleRequired": "Se requiere título", "authorRequired": "El campo Nombre es obligatorio", @@ -538,7 +538,7 @@ "comments": "Comentarios/Preguntas", "cta": "Enviar formulario", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Opcional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "Errors": { "invalidInput": "Por favor, revisa tu opinión y vuelve a intentarlo", "invalidFormat": "El valor introducido no coincide con el formato requerido" diff --git a/core/messages/es-PE.json b/core/messages/es-PE.json index 65c6b149e7..f5e29ab304 100644 --- a/core/messages/es-PE.json +++ b/core/messages/es-PE.json @@ -98,7 +98,7 @@ "heading": "Cuenta nueva", "cta": "Crear cuenta", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "firstNameRequired": "El campo Nombre es obligatorio.", "lastNameRequired": "El campo Apellido es obligatorio.", @@ -506,7 +506,7 @@ "emailLabel": "Correo electrónico", "successMessage": "¡Tu reseña fue enviada con éxito!", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "FieldErrors": { "titleRequired": "Se requiere título", "authorRequired": "El campo Nombre es obligatorio", @@ -538,7 +538,7 @@ "comments": "Comentarios/Preguntas", "cta": "Enviar formulario", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Opcional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Por favor, completa la verificación de reCAPTCHA.", "Errors": { "invalidInput": "Por favor, revisa tu opinión y vuelve a intentarlo", "invalidFormat": "El valor introducido no coincide con el formato requerido" diff --git a/core/messages/es.json b/core/messages/es.json index 3e16cceb32..237518c26e 100644 --- a/core/messages/es.json +++ b/core/messages/es.json @@ -98,7 +98,7 @@ "heading": "Cuenta nueva", "cta": "Crear cuenta", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Completa la verificación de reCAPTCHA.", "FieldErrors": { "firstNameRequired": "El campo Nombre es obligatorio.", "lastNameRequired": "El campo Apellido(s) es obligatorio.", @@ -506,7 +506,7 @@ "emailLabel": "Correo electrónico", "successMessage": "¡Tu reseña se ha enviado correctamente!", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Completa la verificación de reCAPTCHA.", "FieldErrors": { "titleRequired": "El título es obligatorio", "authorRequired": "El campo Nombre es obligatorio", @@ -538,7 +538,7 @@ "comments": "Comentarios/Preguntas", "cta": "Enviar formulario", "somethingWentWrong": "Algo salió mal. Vuelva a intentarlo más tarde.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Completa la verificación de reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "Opcional", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Completa la verificación de reCAPTCHA.", "Errors": { "invalidInput": "Comprueba lo que has escrito e inténtalo de nuevo", "invalidFormat": "El valor introducido no coincide con el formato requerido" diff --git a/core/messages/fr.json b/core/messages/fr.json index 7ac89c3abe..3ec37d0616 100644 --- a/core/messages/fr.json +++ b/core/messages/fr.json @@ -98,7 +98,7 @@ "heading": "Nouveau compte", "cta": "Créer un compte", "somethingWentWrong": "Une erreur s'est produite. Veuillez réessayer plus tard.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Veuillez compléter la vérification reCAPTCHA.", "FieldErrors": { "firstNameRequired": "Le prénom est requis", "lastNameRequired": "Le nom de famille est requis", @@ -506,7 +506,7 @@ "emailLabel": "E-mail", "successMessage": "Votre avis a bien été envoyé !", "somethingWentWrong": "Une erreur s'est produite. Veuillez réessayer plus tard.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Veuillez compléter la vérification reCAPTCHA.", "FieldErrors": { "titleRequired": "Le titre est obligatoire", "authorRequired": "Le nom doit être renseigné", @@ -538,7 +538,7 @@ "comments": "Commentaires/Questions", "cta": "Envoyer le formulaire", "somethingWentWrong": "Une erreur s'est produite. Veuillez réessayer plus tard.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Veuillez compléter la vérification reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "facultatif", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Veuillez compléter la vérification reCAPTCHA.", "Errors": { "invalidInput": "Veuillez vérifier votre saisie et réessayer", "invalidFormat": "La valeur saisie ne correspond pas au format requis" diff --git a/core/messages/it.json b/core/messages/it.json index 75179721ec..ea6727e90d 100644 --- a/core/messages/it.json +++ b/core/messages/it.json @@ -98,7 +98,7 @@ "heading": "Nuovo account", "cta": "Crea account", "somethingWentWrong": "Si è verificato un errore. Riprova più tardi.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Completa la verifica reCAPTCHA.", "FieldErrors": { "firstNameRequired": "Il nome è obbligatorio", "lastNameRequired": "Il cognome è obbligatorio", @@ -506,7 +506,7 @@ "emailLabel": "E-mail", "successMessage": "La tua recensione è stata inviata correttamente.", "somethingWentWrong": "Si è verificato un errore. Riprova più tardi.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Completa la verifica reCAPTCHA.", "FieldErrors": { "titleRequired": "Il titolo è obbligatorio", "authorRequired": "Il nome è obbligatorio", @@ -538,7 +538,7 @@ "comments": "Commenti/domande", "cta": "Invia modulo", "somethingWentWrong": "Si è verificato un errore. Riprova più tardi.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Completa la verifica reCAPTCHA." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "facoltativo", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Completa la verifica reCAPTCHA.", "Errors": { "invalidInput": "Controlla i dati inseriti e riprova", "invalidFormat": "Il valore inserito non corrisponde al formato richiesto" diff --git a/core/messages/ja.json b/core/messages/ja.json index 5d20172283..97e12f125b 100644 --- a/core/messages/ja.json +++ b/core/messages/ja.json @@ -98,7 +98,7 @@ "heading": "新しいアカウント", "cta": "アカウント作成", "somethingWentWrong": "何か問題が発生しました。後でもう一度やり直してください。", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "reCAPTCHA認証を完了してください。", "FieldErrors": { "firstNameRequired": "名は必須です", "lastNameRequired": "姓は必須です", @@ -506,7 +506,7 @@ "emailLabel": "Eメール", "successMessage": "レビューは正常に送信されました。", "somethingWentWrong": "何か問題が発生しました。後でもう一度やり直してください。", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "reCAPTCHA認証を完了してください。", "FieldErrors": { "titleRequired": "タイトルは必須です", "authorRequired": "商品名は必須です", @@ -538,7 +538,7 @@ "comments": "コメント/質問", "cta": "フォームを送信", "somethingWentWrong": "何か問題が発生しました。後でもう一度やり直してください。", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "reCAPTCHA認証を完了してください。" } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "オプション", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "reCAPTCHA認証を完了してください。", "Errors": { "invalidInput": "入力内容を確認してもう一度お試しください", "invalidFormat": "入力された値は必要な形式と一致しません" diff --git a/core/messages/nl.json b/core/messages/nl.json index 659e383573..e80281d234 100644 --- a/core/messages/nl.json +++ b/core/messages/nl.json @@ -98,7 +98,7 @@ "heading": "Nieuw account", "cta": "Account aanmaken", "somethingWentWrong": "Er is iets fout gegaan. Probeer het later opnieuw.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Voltooi de reCAPTCHA-verificatie.", "FieldErrors": { "firstNameRequired": "Voornaam is vereist", "lastNameRequired": "Achternaam is vereist", @@ -506,7 +506,7 @@ "emailLabel": "E-mailadres", "successMessage": "Je beoordeling is succesvol ingediend!", "somethingWentWrong": "Er is iets fout gegaan. Probeer het later opnieuw.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Voltooi de reCAPTCHA-verificatie.", "FieldErrors": { "titleRequired": "Titel is vereist", "authorRequired": "Naam is verplicht", @@ -538,7 +538,7 @@ "comments": "Opmerkingen/vragen", "cta": "Formulier indienen", "somethingWentWrong": "Er is iets fout gegaan. Probeer het later opnieuw.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Voltooi de reCAPTCHA-verificatie." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "optioneel", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Voltooi de reCAPTCHA-verificatie.", "Errors": { "invalidInput": "Controleer uw invoer en probeer het opnieuw", "invalidFormat": "De ingevoerde waarde komt niet overeen met het vereiste formaat" diff --git a/core/messages/no.json b/core/messages/no.json index 22e4cc123a..dc74691519 100644 --- a/core/messages/no.json +++ b/core/messages/no.json @@ -98,7 +98,7 @@ "heading": "Ny konto", "cta": "Opprett konto", "somethingWentWrong": "Noe gikk galt. Prøv igjen senere.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Fullfør reCAPTCHA-verifiseringen.", "FieldErrors": { "firstNameRequired": "Fornavn er påkrevd", "lastNameRequired": "Etternavn er påkrevd", @@ -506,7 +506,7 @@ "emailLabel": "E-post", "successMessage": "Din anmeldelse er sendt inn!", "somethingWentWrong": "Noe gikk galt. Prøv igjen senere.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Fullfør reCAPTCHA-verifiseringen.", "FieldErrors": { "titleRequired": "Tittel er påkrevd", "authorRequired": "Navn er påkrevd", @@ -538,7 +538,7 @@ "comments": "Kommentarer/spørsmål", "cta": "Send inn skjema", "somethingWentWrong": "Noe gikk galt. Prøv igjen senere.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Fullfør reCAPTCHA-verifiseringen." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "valgfri", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Fullfør reCAPTCHA-verifiseringen.", "Errors": { "invalidInput": "Sjekk inndataene dine og prøv igjen", "invalidFormat": "Den angitte verdien samsvarer ikke med det nødvendige formatet" diff --git a/core/messages/sv.json b/core/messages/sv.json index 778c64475d..7fc883ce72 100644 --- a/core/messages/sv.json +++ b/core/messages/sv.json @@ -98,7 +98,7 @@ "heading": "Nytt konto", "cta": "Skapa konto", "somethingWentWrong": "Någonting gick fel. Vänligen försök igen senare.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Slutför reCAPTCHA-verifieringen.", "FieldErrors": { "firstNameRequired": "Förnamn krävs", "lastNameRequired": "Efternamn krävs", @@ -506,7 +506,7 @@ "emailLabel": "E-post", "successMessage": "Din recension har skickats in!", "somethingWentWrong": "Någonting gick fel. Vänligen försök igen senare.", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Slutför reCAPTCHA-verifieringen.", "FieldErrors": { "titleRequired": "Rubrik krävs", "authorRequired": "Namn krävs", @@ -538,7 +538,7 @@ "comments": "Kommentarer/frågor", "cta": "Skicka formulär", "somethingWentWrong": "Någonting gick fel. Vänligen försök igen senare.", - "recaptchaRequired": "Please complete the reCAPTCHA verification." + "recaptchaRequired": "Slutför reCAPTCHA-verifieringen." } } }, @@ -708,7 +708,7 @@ }, "Form": { "optional": "frivillig", - "recaptchaRequired": "Please complete the reCAPTCHA verification.", + "recaptchaRequired": "Slutför reCAPTCHA-verifieringen.", "Errors": { "invalidInput": "Kontrollera det som angetts och försök igen", "invalidFormat": "Det inmatade värdet stämmer inte överens med det format som krävs" From e198d8966d589bd6707cdb1588986c9c092d73be Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 24 Mar 2026 08:21:18 -0500 Subject: [PATCH 12/47] fix(core): adds root-level not found page (#2947) --- .changeset/fix-root-not-found.md | 5 +++ core/app/[locale]/layout.tsx | 58 ++++++++++++++------------------ core/app/layout.tsx | 14 ++++++++ core/app/not-found.tsx | 22 ++++++++++++ 4 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 .changeset/fix-root-not-found.md create mode 100644 core/app/layout.tsx create mode 100644 core/app/not-found.tsx diff --git a/.changeset/fix-root-not-found.md b/.changeset/fix-root-not-found.md new file mode 100644 index 0000000000..0fe33621e2 --- /dev/null +++ b/.changeset/fix-root-not-found.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Add root-level not-found page so /404 renders a branded page instead of the default Vercel error screen diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index f0a08d7f3f..11d3d88e85 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -1,6 +1,5 @@ import { Analytics } from '@vercel/analytics/react'; import { SpeedInsights } from '@vercel/speed-insights/next'; -import { clsx } from 'clsx'; import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { NextIntlClientProvider } from 'next-intl'; @@ -8,9 +7,6 @@ import { setRequestLocale } from 'next-intl/server'; import { NuqsAdapter } from 'nuqs/adapters/next/app'; import { cache, PropsWithChildren } from 'react'; -import '../../globals.css'; - -import { fonts } from '~/app/fonts'; import { CookieNotifications } from '~/app/notifications'; import { Providers } from '~/app/providers'; import { client } from '~/client'; @@ -140,34 +136,32 @@ export default async function RootLayout({ params, children }: Props) { const privacyPolicyUrl = rootData.data.site.settings?.privacy?.privacyPolicyUrl; return ( - f.variable))} lang={locale}> - - - - - - - {toastNotificationCookieData && ( - - )} - {children} - - - - - - - - - + <> + + + + + + {toastNotificationCookieData && ( + + )} + {children} + + + + + + + + ); } diff --git a/core/app/layout.tsx b/core/app/layout.tsx new file mode 100644 index 0000000000..ea754b0fb4 --- /dev/null +++ b/core/app/layout.tsx @@ -0,0 +1,14 @@ +import { clsx } from 'clsx'; +import { PropsWithChildren } from 'react'; + +import '../globals.css'; + +import { fonts } from '~/app/fonts'; + +export default function RootLayout({ children }: PropsWithChildren) { + return ( + f.variable))} lang="en"> + {children} + + ); +} diff --git a/core/app/not-found.tsx b/core/app/not-found.tsx new file mode 100644 index 0000000000..8651b7547c --- /dev/null +++ b/core/app/not-found.tsx @@ -0,0 +1,22 @@ +export default function RootNotFound() { + return ( +
+
+
+

+ Not found +

+

+ The page you are looking for could not be found. +

+ + Go to homepage + +
+
+
+ ); +} From 66d2a7dfab653762da4986b55a7c92fa4ab9b6c6 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 25 Mar 2026 13:04:11 -0500 Subject: [PATCH 13/47] feat: upgrade @makeswift/runtime to 0.28.2 (#2952) --- .changeset/upgrade-makeswift-runtime.md | 5 +++++ core/app/api/makeswift/[...makeswift]/route.ts | 2 -- core/lib/makeswift/client.ts | 1 - core/lib/makeswift/provider.tsx | 7 +------ core/lib/makeswift/runtime.ts | 3 +++ core/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 7 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 .changeset/upgrade-makeswift-runtime.md diff --git a/.changeset/upgrade-makeswift-runtime.md b/.changeset/upgrade-makeswift-runtime.md new file mode 100644 index 0000000000..0a0bb54ca5 --- /dev/null +++ b/.changeset/upgrade-makeswift-runtime.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-makeswift": minor +--- + +Upgrade `@makeswift/runtime` from `0.26.3` to `0.28.2`. The `apiOrigin` and `appOrigin` configuration now lives on the `ReactRuntimeCore` constructor instead of being passed separately to `ReactRuntimeProvider`, `Makeswift` client, and `MakeswiftApiHandler`. diff --git a/core/app/api/makeswift/[...makeswift]/route.ts b/core/app/api/makeswift/[...makeswift]/route.ts index 375dc590ef..d860a0a3e4 100644 --- a/core/app/api/makeswift/[...makeswift]/route.ts +++ b/core/app/api/makeswift/[...makeswift]/route.ts @@ -24,8 +24,6 @@ const defaultVariants: Font['variants'] = [ const handler = MakeswiftApiHandler(process.env.MAKESWIFT_SITE_API_KEY, { runtime, - apiOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_API_ORIGIN ?? process.env.MAKESWIFT_API_ORIGIN, - appOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_APP_ORIGIN ?? process.env.MAKESWIFT_APP_ORIGIN, getFonts() { return [ { diff --git a/core/lib/makeswift/client.ts b/core/lib/makeswift/client.ts index 9a637384ca..cc2a7eced4 100644 --- a/core/lib/makeswift/client.ts +++ b/core/lib/makeswift/client.ts @@ -11,7 +11,6 @@ strict(process.env.MAKESWIFT_SITE_API_KEY, 'MAKESWIFT_SITE_API_KEY is required') export const client = new Makeswift(process.env.MAKESWIFT_SITE_API_KEY, { runtime, - apiOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_API_ORIGIN ?? process.env.MAKESWIFT_API_ORIGIN, }); export const getPageSnapshot = async ({ path, locale }: { path: string; locale: string }) => diff --git a/core/lib/makeswift/provider.tsx b/core/lib/makeswift/provider.tsx index 8377ff9443..a87e511e29 100644 --- a/core/lib/makeswift/provider.tsx +++ b/core/lib/makeswift/provider.tsx @@ -13,12 +13,7 @@ export function MakeswiftProvider({ siteVersion: SiteVersion | null; }) { return ( - + {children} ); diff --git a/core/lib/makeswift/runtime.ts b/core/lib/makeswift/runtime.ts index 7956ee8307..9ea4144b0a 100644 --- a/core/lib/makeswift/runtime.ts +++ b/core/lib/makeswift/runtime.ts @@ -10,12 +10,15 @@ import { registerVideoComponent } from '@makeswift/runtime/react/builtins/video' import { ReactRuntimeCore } from '@makeswift/runtime/react/core'; const runtime = new ReactRuntimeCore({ + apiOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_API_ORIGIN ?? process.env.MAKESWIFT_API_ORIGIN, + appOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_APP_ORIGIN ?? process.env.MAKESWIFT_APP_ORIGIN, breakpoints: { small: { width: 640, viewport: 390, label: 'Small' }, medium: { width: 768, viewport: 765, label: 'Medium' }, large: { width: 1024, viewport: 1000, label: 'Large' }, screen: { width: 1280, label: 'XL' }, }, + fetch, }); // Only register necessary built-in components. Omitted components are: diff --git a/core/package.json b/core/package.json index bc97ba687d..e8c9024489 100644 --- a/core/package.json +++ b/core/package.json @@ -22,7 +22,7 @@ "@conform-to/react": "^1.6.1", "@conform-to/zod": "^1.6.1", "@icons-pack/react-simple-icons": "^11.2.0", - "@makeswift/runtime": "^0.26.3", + "@makeswift/runtime": "0.28.2", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.208.0", "@opentelemetry/instrumentation": "^0.208.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 383929eec9..8dc45e7548 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,8 +54,8 @@ importers: specifier: ^11.2.0 version: 11.2.0(react@19.1.5) '@makeswift/runtime': - specifier: ^0.26.3 - version: 0.26.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + specifier: 0.28.2 + version: 0.28.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5) '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -2563,8 +2563,8 @@ packages: '@makeswift/prop-controllers@0.4.10': resolution: {integrity: sha512-rqiUsEKe+3I0eyJNosTuef3Z0FG3UnPz6rOXY2G7SbKk1h+jyKGVulNPVmsafM9SzuMTfzZNtNL0ouDRsQym+Q==} - '@makeswift/runtime@0.26.3': - resolution: {integrity: sha512-zDvTmiUHsbYI2a2FUpFV6LPSNgTVsmUuX8pCbrvuJyoloXNMu9JPMtNiyay50Rq7+w2tvycfMcacJYQIyct0PA==} + '@makeswift/runtime@0.28.2': + resolution: {integrity: sha512-ZzF2yZoBeuDTPOFbj5ZPyyifHjgxGAvZ2HYxQ45P2vVlOi7c1nenYua/u8FfQTQBjEjzhD16m/8JSYr0VHIb1A==} engines: {node: '>=20.0.0'} peerDependencies: '@types/react': ^18.0.0 || ^19.0.0 @@ -13733,7 +13733,7 @@ snapshots: ts-pattern: 5.9.0 zod: 3.25.51 - '@makeswift/runtime@0.26.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@makeswift/runtime@0.28.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': dependencies: '@emotion/cache': 11.14.0 '@emotion/css': 11.13.5 From 30ac2ab900ed36f9053cad663d5d4b98dd8838bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 18:12:43 +0000 Subject: [PATCH 14/47] Version Packages (`canary`) (#2946) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/fix-root-not-found.md | 5 ----- .changeset/translations-patch-5c63d5bb.md | 5 ----- core/CHANGELOG.md | 8 ++++++++ core/package.json | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) delete mode 100644 .changeset/fix-root-not-found.md delete mode 100644 .changeset/translations-patch-5c63d5bb.md diff --git a/.changeset/fix-root-not-found.md b/.changeset/fix-root-not-found.md deleted file mode 100644 index 0fe33621e2..0000000000 --- a/.changeset/fix-root-not-found.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bigcommerce/catalyst-core": patch ---- - -Add root-level not-found page so /404 renders a branded page instead of the default Vercel error screen diff --git a/.changeset/translations-patch-5c63d5bb.md b/.changeset/translations-patch-5c63d5bb.md deleted file mode 100644 index ad17b2636a..0000000000 --- a/.changeset/translations-patch-5c63d5bb.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bigcommerce/catalyst-core": patch ---- - -Update translations. diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index c15a19559e..eb51225d48 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.6.2 + +### Patch Changes + +- [#2947](https://github.com/bigcommerce/catalyst/pull/2947) [`e198d89`](https://github.com/bigcommerce/catalyst/commit/e198d8966d589bd6707cdb1588986c9c092d73be) Thanks [@jorgemoya](https://github.com/jorgemoya)! - Add root-level not-found page so /404 renders a branded page instead of the default Vercel error screen + +- [#2945](https://github.com/bigcommerce/catalyst/pull/2945) [`4479964`](https://github.com/bigcommerce/catalyst/commit/447996400e6fcc6388937011e101d802308e6b33) Thanks [@bc-svc-local](https://github.com/bc-svc-local)! - Update translations. + ## 1.6.1 ### Patch Changes diff --git a/core/package.json b/core/package.json index 2a4fd29e81..f85f9c2a73 100644 --- a/core/package.json +++ b/core/package.json @@ -1,7 +1,7 @@ { "name": "@bigcommerce/catalyst-core", "description": "BigCommerce Catalyst is a Next.js starter kit for building headless BigCommerce storefronts.", - "version": "1.6.1", + "version": "1.6.2", "private": true, "engines": { "node": ">=24.0.0" From ebb5ec60080b4c0b1aa4d01b8998d83a4ecea3ff Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 25 Mar 2026 14:15:56 -0500 Subject: [PATCH 15/47] chore: change @makeswift/runtime to 0.26.4 (#2955) --- .changeset/upgrade-makeswift-runtime.md | 4 ++-- core/app/api/makeswift/[...makeswift]/route.ts | 2 ++ core/lib/makeswift/client.ts | 1 + core/lib/makeswift/provider.tsx | 7 ++++++- core/lib/makeswift/runtime.ts | 3 --- core/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 7 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.changeset/upgrade-makeswift-runtime.md b/.changeset/upgrade-makeswift-runtime.md index 0a0bb54ca5..0aed5f70ce 100644 --- a/.changeset/upgrade-makeswift-runtime.md +++ b/.changeset/upgrade-makeswift-runtime.md @@ -1,5 +1,5 @@ --- -"@bigcommerce/catalyst-makeswift": minor +"@bigcommerce/catalyst-makeswift": patch --- -Upgrade `@makeswift/runtime` from `0.26.3` to `0.28.2`. The `apiOrigin` and `appOrigin` configuration now lives on the `ReactRuntimeCore` constructor instead of being passed separately to `ReactRuntimeProvider`, `Makeswift` client, and `MakeswiftApiHandler`. +Upgrade `@makeswift/runtime` from `0.26.3` to `0.26.4`. diff --git a/core/app/api/makeswift/[...makeswift]/route.ts b/core/app/api/makeswift/[...makeswift]/route.ts index d860a0a3e4..375dc590ef 100644 --- a/core/app/api/makeswift/[...makeswift]/route.ts +++ b/core/app/api/makeswift/[...makeswift]/route.ts @@ -24,6 +24,8 @@ const defaultVariants: Font['variants'] = [ const handler = MakeswiftApiHandler(process.env.MAKESWIFT_SITE_API_KEY, { runtime, + apiOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_API_ORIGIN ?? process.env.MAKESWIFT_API_ORIGIN, + appOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_APP_ORIGIN ?? process.env.MAKESWIFT_APP_ORIGIN, getFonts() { return [ { diff --git a/core/lib/makeswift/client.ts b/core/lib/makeswift/client.ts index cc2a7eced4..9a637384ca 100644 --- a/core/lib/makeswift/client.ts +++ b/core/lib/makeswift/client.ts @@ -11,6 +11,7 @@ strict(process.env.MAKESWIFT_SITE_API_KEY, 'MAKESWIFT_SITE_API_KEY is required') export const client = new Makeswift(process.env.MAKESWIFT_SITE_API_KEY, { runtime, + apiOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_API_ORIGIN ?? process.env.MAKESWIFT_API_ORIGIN, }); export const getPageSnapshot = async ({ path, locale }: { path: string; locale: string }) => diff --git a/core/lib/makeswift/provider.tsx b/core/lib/makeswift/provider.tsx index a87e511e29..8377ff9443 100644 --- a/core/lib/makeswift/provider.tsx +++ b/core/lib/makeswift/provider.tsx @@ -13,7 +13,12 @@ export function MakeswiftProvider({ siteVersion: SiteVersion | null; }) { return ( - + {children} ); diff --git a/core/lib/makeswift/runtime.ts b/core/lib/makeswift/runtime.ts index 9ea4144b0a..7956ee8307 100644 --- a/core/lib/makeswift/runtime.ts +++ b/core/lib/makeswift/runtime.ts @@ -10,15 +10,12 @@ import { registerVideoComponent } from '@makeswift/runtime/react/builtins/video' import { ReactRuntimeCore } from '@makeswift/runtime/react/core'; const runtime = new ReactRuntimeCore({ - apiOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_API_ORIGIN ?? process.env.MAKESWIFT_API_ORIGIN, - appOrigin: process.env.NEXT_PUBLIC_MAKESWIFT_APP_ORIGIN ?? process.env.MAKESWIFT_APP_ORIGIN, breakpoints: { small: { width: 640, viewport: 390, label: 'Small' }, medium: { width: 768, viewport: 765, label: 'Medium' }, large: { width: 1024, viewport: 1000, label: 'Large' }, screen: { width: 1280, label: 'XL' }, }, - fetch, }); // Only register necessary built-in components. Omitted components are: diff --git a/core/package.json b/core/package.json index e8c9024489..2532731d8d 100644 --- a/core/package.json +++ b/core/package.json @@ -22,7 +22,7 @@ "@conform-to/react": "^1.6.1", "@conform-to/zod": "^1.6.1", "@icons-pack/react-simple-icons": "^11.2.0", - "@makeswift/runtime": "0.28.2", + "@makeswift/runtime": "0.26.4", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.208.0", "@opentelemetry/instrumentation": "^0.208.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8dc45e7548..2d05ff4203 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,8 +54,8 @@ importers: specifier: ^11.2.0 version: 11.2.0(react@19.1.5) '@makeswift/runtime': - specifier: 0.28.2 - version: 0.28.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + specifier: 0.26.4 + version: 0.26.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5) '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -2563,8 +2563,8 @@ packages: '@makeswift/prop-controllers@0.4.10': resolution: {integrity: sha512-rqiUsEKe+3I0eyJNosTuef3Z0FG3UnPz6rOXY2G7SbKk1h+jyKGVulNPVmsafM9SzuMTfzZNtNL0ouDRsQym+Q==} - '@makeswift/runtime@0.28.2': - resolution: {integrity: sha512-ZzF2yZoBeuDTPOFbj5ZPyyifHjgxGAvZ2HYxQ45P2vVlOi7c1nenYua/u8FfQTQBjEjzhD16m/8JSYr0VHIb1A==} + '@makeswift/runtime@0.26.4': + resolution: {integrity: sha512-hCmXv5h94j+MMOgPh7F0yteFvGOmSztlr6tTjrPEfxr9OCwr+gmE3crlXgO/SQW34NtQXVZLtg5ZcCoD6kFzlw==} engines: {node: '>=20.0.0'} peerDependencies: '@types/react': ^18.0.0 || ^19.0.0 @@ -13733,7 +13733,7 @@ snapshots: ts-pattern: 5.9.0 zod: 3.25.51 - '@makeswift/runtime@0.28.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@makeswift/runtime@0.26.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': dependencies: '@emotion/cache': 11.14.0 '@emotion/css': 11.13.5 From 0037866fe06599d23ae80c5e221a27bcc88862f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 14:25:10 -0500 Subject: [PATCH 16/47] Version Packages (`integrations/makeswift`) (#2953) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/upgrade-makeswift-runtime.md | 5 ----- core/CHANGELOG.md | 6 ++++++ core/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/upgrade-makeswift-runtime.md diff --git a/.changeset/upgrade-makeswift-runtime.md b/.changeset/upgrade-makeswift-runtime.md deleted file mode 100644 index 0aed5f70ce..0000000000 --- a/.changeset/upgrade-makeswift-runtime.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bigcommerce/catalyst-makeswift": patch ---- - -Upgrade `@makeswift/runtime` from `0.26.3` to `0.26.4`. diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index e5ebb3360b..342405d1d2 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.6.3 + +### Patch Changes + +- [#2952](https://github.com/bigcommerce/catalyst/pull/2952) [`66d2a7d`](https://github.com/bigcommerce/catalyst/commit/66d2a7dfab653762da4986b55a7c92fa4ab9b6c6) Thanks [@jorgemoya](https://github.com/jorgemoya)! - Upgrade `@makeswift/runtime` from `0.26.3` to `0.26.4`. + ## 1.6.2 ### Patch Changes diff --git a/core/package.json b/core/package.json index 2532731d8d..f0a3e55870 100644 --- a/core/package.json +++ b/core/package.json @@ -1,7 +1,7 @@ { "name": "@bigcommerce/catalyst-makeswift", "description": "BigCommerce Catalyst is a Next.js starter kit for building headless BigCommerce storefronts.", - "version": "1.6.2", + "version": "1.6.3", "private": true, "engines": { "node": ">=24.0.0" From 620ac0e627bd21da06f27af07f206abfae72a82e Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Wed, 25 Mar 2026 14:34:04 -0500 Subject: [PATCH 17/47] fix(core): pin next to ~16.1.6 to prevent 16.2 bumps (#2956) Use tilde range to allow patch updates but block minor bumps to 16.2, which introduces deployment issues on Cloudflare Workers. --- core/package.json | 2 +- pnpm-lock.yaml | 92 +++++++++++------------------------------------ 2 files changed, 22 insertions(+), 72 deletions(-) diff --git a/core/package.json b/core/package.json index f85f9c2a73..d9b6cd3a34 100644 --- a/core/package.json +++ b/core/package.json @@ -60,7 +60,7 @@ "lodash.debounce": "^4.0.8", "lru-cache": "^11.1.0", "lucide-react": "^0.474.0", - "next": "^16.1.6", + "next": "~16.1.6", "next-auth": "5.0.0-beta.30", "next-intl": "^4.6.1", "nuqs": "^2.4.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 24c3141c1c..18248ad97d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -168,7 +168,7 @@ importers: specifier: ^0.474.0 version: 0.474.0(react@19.1.5) next: - specifier: ^16.1.6 + specifier: ~16.1.6 version: 16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) next-auth: specifier: 5.0.0-beta.30 @@ -5305,6 +5305,7 @@ packages: basic-ftp@5.0.5: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} + deprecated: Security vulnerability fixed in 5.2.0, please upgrade better-opn@3.0.2: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} @@ -6826,20 +6827,23 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@11.0.3: resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} engines: {node: '>=16 || 14 >=14.17'} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -8838,7 +8842,7 @@ packages: puppeteer@24.10.0: resolution: {integrity: sha512-Oua9VkGpj0S2psYu5e6mCer6W9AU9POEQh22wRgSXnLXASGH+MwLUVWgLCLeP9QPHHcJ7tySUlg4Sa9OJmaLpw==} engines: {node: '>=18'} - deprecated: < 24.10.2 is no longer supported + deprecated: < 24.15.0 is no longer supported hasBin: true pure-rand@6.1.0: @@ -9523,6 +9527,7 @@ packages: tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} @@ -10136,6 +10141,7 @@ packages: whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} @@ -11661,9 +11667,9 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-config-prettier: 9.1.0(eslint@8.57.1) - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) eslint-plugin-gettext: 1.2.0 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) eslint-plugin-jest: 28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) eslint-plugin-jest-dom: 5.5.0(eslint@8.57.1) eslint-plugin-jest-formatting: 3.1.0(eslint@8.57.1) @@ -12835,7 +12841,7 @@ snapshots: '@img/sharp-wasm32@0.33.5': dependencies: - '@emnapi/runtime': 1.4.5 + '@emnapi/runtime': 1.9.0 optional: true '@img/sharp-wasm32@0.34.5': @@ -13972,7 +13978,7 @@ snapshots: extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.5.0 - semver: 7.7.2 + semver: 7.7.4 tar-fs: 3.0.9 unbzip2-stream: 1.4.3 yargs: 17.7.2 @@ -17703,8 +17709,8 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -17731,21 +17737,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1): - dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.1 - eslint: 8.57.1 - get-tsconfig: 4.10.0 - is-bun-module: 1.3.0 - rspack-resolver: 1.2.2 - stable-hash: 0.0.5 - tinyglobby: 0.2.14 - optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) - transitivePeerDependencies: - - supports-color - eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 @@ -17762,17 +17753,6 @@ snapshots: - supports-color eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -17793,35 +17773,6 @@ snapshots: dependencies: gettext-parser: 4.2.0 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 @@ -17833,7 +17784,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -18375,7 +18326,7 @@ snapshots: commander: 14.0.0 kysely: 0.28.8 kysely-typeorm: 0.3.0(kysely@0.28.8)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3))) - semver: 7.7.2 + semver: 7.7.4 zod: 4.1.12 optionalDependencies: drizzle-orm: 0.44.7(@opentelemetry/api@1.9.0)(@upstash/redis@1.35.0)(kysely@0.27.6) @@ -19002,7 +18953,7 @@ snapshots: '@babel/parser': 7.28.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.2 + semver: 7.7.4 transitivePeerDependencies: - supports-color @@ -19461,7 +19412,7 @@ snapshots: dependencies: cssstyle: 4.3.1 data-urls: 5.0.0 - decimal.js: 10.5.0 + decimal.js: 10.6.0 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -21160,8 +21111,7 @@ snapshots: semver@7.7.2: {} - semver@7.7.4: - optional: true + semver@7.7.4: {} send@1.2.0: dependencies: @@ -21226,7 +21176,7 @@ snapshots: dependencies: color: 4.2.3 detect-libc: 2.1.2 - semver: 7.7.2 + semver: 7.7.4 optionalDependencies: '@img/sharp-darwin-arm64': 0.33.5 '@img/sharp-darwin-x64': 0.33.5 From 1a2b1426afe1a2f68466421a795b17eab655e9c2 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Mon, 30 Mar 2026 12:45:29 -0500 Subject: [PATCH 18/47] fix: improve regression-tests workflow structure and concurrency (#2948) * fix: split regression-tests workflow into two separate flows * fix: merge back to a single file * use deployments.ref for PRs --- .github/workflows/regression-tests.yml | 56 ++++++++++---------------- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/.github/workflows/regression-tests.yml b/.github/workflows/regression-tests.yml index ec122b1b91..dd4338a274 100644 --- a/.github/workflows/regression-tests.yml +++ b/.github/workflows/regression-tests.yml @@ -7,20 +7,15 @@ on: env: VERCEL_PROTECTION_BYPASS: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }} -concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.deployment_status.target_url }} - cancel-in-progress: true - jobs: detect-provider: name: Detect Deployment Provider runs-on: ubuntu-latest outputs: provider: ${{ steps.detect.outputs.provider }} - is-preview: ${{ steps.detect.outputs.is-preview }} production-url: ${{ steps.detect.outputs.production-url }} - is-canary-branch: ${{ steps.detect.outputs.is-canary-branch }} branch-label: ${{ steps.detect.outputs.branch-label }} + is-preview: ${{ steps.detect.outputs.is-preview }} steps: - uses: actions/checkout@v4 @@ -30,13 +25,17 @@ jobs: CREATOR="${{ github.event.deployment_status.creator.login }}" ENVIRONMENT="${{ github.event.deployment.environment }}" + if [[ "$ENVIRONMENT" == "Preview" ]]; then + echo "is-preview=true" >> $GITHUB_OUTPUT + else + echo "is-preview=false" >> $GITHUB_OUTPUT + fi + if [[ "$CREATOR" == "vercel[bot]" ]]; then echo "provider=vercel" >> $GITHUB_OUTPUT + PKG_NAME=$(node -p "require('./core/package.json').name") + if [[ "$ENVIRONMENT" == "Preview" ]]; then - echo "is-preview=true" >> $GITHUB_OUTPUT - echo "is-canary-branch=false" >> $GITHUB_OUTPUT - echo "branch-label=" >> $GITHUB_OUTPUT - PKG_NAME=$(node -p "require('./core/package.json').name") case "$PKG_NAME" in "@bigcommerce/catalyst-core") echo "production-url=https://canary.catalyst-demo.site/" >> $GITHUB_OUTPUT ;; @@ -46,20 +45,16 @@ jobs: echo "::warning::No production URL configured for package: $PKG_NAME. Skipping comparison." echo "production-url=" >> $GITHUB_OUTPUT ;; esac + echo "branch-label=" >> $GITHUB_OUTPUT else - PKG_NAME=$(node -p "require('./core/package.json').name") - echo "is-preview=false" >> $GITHUB_OUTPUT case "$PKG_NAME" in "@bigcommerce/catalyst-core") - echo "is-canary-branch=true" >> $GITHUB_OUTPUT echo "branch-label=canary" >> $GITHUB_OUTPUT echo "production-url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT ;; "@bigcommerce/catalyst-makeswift") - echo "is-canary-branch=true" >> $GITHUB_OUTPUT echo "branch-label=integrations/makeswift" >> $GITHUB_OUTPUT echo "production-url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT ;; *) - echo "is-canary-branch=false" >> $GITHUB_OUTPUT echo "branch-label=" >> $GITHUB_OUTPUT echo "production-url=" >> $GITHUB_OUTPUT ;; esac @@ -67,24 +62,15 @@ jobs: elif [[ "$CREATOR" == "cloudflare-pages[bot]" ]]; then echo "provider=cloudflare" >> $GITHUB_OUTPUT - echo "is-canary-branch=false" >> $GITHUB_OUTPUT + echo "::warning::Cloudflare production URL not yet configured. Skipping comparison." + echo "production-url=" >> $GITHUB_OUTPUT echo "branch-label=" >> $GITHUB_OUTPUT - if [[ "$ENVIRONMENT" == "Preview" ]]; then - echo "is-preview=true" >> $GITHUB_OUTPUT - echo "::warning::Cloudflare production URL not yet configured. Skipping comparison." - echo "production-url=" >> $GITHUB_OUTPUT - else - echo "is-preview=false" >> $GITHUB_OUTPUT - echo "production-url=" >> $GITHUB_OUTPUT - fi else echo "::warning::Unknown deployment provider: $CREATOR. Skipping audits." echo "provider=unknown" >> $GITHUB_OUTPUT - echo "is-preview=false" >> $GITHUB_OUTPUT - echo "is-canary-branch=false" >> $GITHUB_OUTPUT - echo "branch-label=" >> $GITHUB_OUTPUT echo "production-url=" >> $GITHUB_OUTPUT + echo "branch-label=" >> $GITHUB_OUTPUT fi unlighthouse-audit-preview: @@ -92,12 +78,12 @@ jobs: needs: [detect-provider] if: needs.detect-provider.outputs.is-preview == 'true' runs-on: ubuntu-latest + concurrency: + group: regression-preview-${{ github.event.deployment.ref }}-${{ matrix.device }} + cancel-in-progress: true strategy: matrix: device: [desktop, mobile] - concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.deployment_status.target_url }}-${{ matrix.device }} - cancel-in-progress: true steps: - uses: actions/checkout@v4 @@ -130,14 +116,14 @@ jobs: unlighthouse-audit-production: name: Unlighthouse Audit Production (${{ needs.detect-provider.outputs.provider }}) - ${{ matrix.device }} needs: [detect-provider] - if: (needs.detect-provider.outputs.is-preview == 'true' && needs.detect-provider.outputs.production-url != '') || needs.detect-provider.outputs.is-canary-branch == 'true' + if: needs.detect-provider.outputs.production-url != '' runs-on: ubuntu-latest + concurrency: + group: regression-production-${{ github.event.deployment.environment == 'Preview' && github.event.deployment.ref || github.event.deployment.sha }}-${{ matrix.device }} + cancel-in-progress: ${{ github.event.deployment.environment == 'Preview' }} strategy: matrix: device: [desktop, mobile] - concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-production-${{ matrix.device }} - cancel-in-progress: true steps: - uses: actions/checkout@v4 @@ -210,7 +196,7 @@ jobs: unlighthouse-report: name: Unlighthouse Report (${{ needs.detect-provider.outputs.provider }}) — ${{ needs.detect-provider.outputs.branch-label }} needs: [detect-provider, unlighthouse-audit-production] - if: needs.detect-provider.outputs.is-canary-branch == 'true' + if: needs.detect-provider.outputs.is-preview == 'false' && needs.detect-provider.outputs.production-url != '' runs-on: ubuntu-latest permissions: contents: write From 4870221c3a5c5209b58fb6ec969b30897d08eea8 Mon Sep 17 00:00:00 2001 From: bc-svc-local <102379007+bc-svc-local@users.noreply.github.com> Date: Mon, 30 Mar 2026 19:52:13 +0200 Subject: [PATCH 19/47] Update translations (#2959) * feat(other): LOCAL-1444 delivery translation * chore(core): create translations patch --------- Co-authored-by: bc-svc-local --- .changeset/translations-patch-d3abeec7.md | 5 +++++ core/messages/pl.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/translations-patch-d3abeec7.md diff --git a/.changeset/translations-patch-d3abeec7.md b/.changeset/translations-patch-d3abeec7.md new file mode 100644 index 0000000000..ad17b2636a --- /dev/null +++ b/.changeset/translations-patch-d3abeec7.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Update translations. diff --git a/core/messages/pl.json b/core/messages/pl.json index 371e78397c..564f17e722 100644 --- a/core/messages/pl.json +++ b/core/messages/pl.json @@ -75,7 +75,7 @@ "CreateAccount": { "title": "Nowy klient?", "accountBenefits": "Załóż u nas konto, a będziesz mógł:", - "fastCheckout": "Sprawdź szybciej", + "fastCheckout": "Do kasy szybciej", "multipleAddresses": "Zapisz wiele adresów wysyłki", "ordersHistory": "Dostęp do historii zamówień", "ordersTracking": "Śledzenie nowych zamówień", From 09f649b7a98ea86972f22a2c9405a8b59fea5f9c Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Tue, 31 Mar 2026 10:34:20 -0500 Subject: [PATCH 20/47] chore: add deployment for native hosting (#2835) * chore: add deployment for native hosting * chore: fix native hosting workflow for alpha CLI - Remove pull_request trigger (no preview deployments) - Add concurrency group to prevent parallel deploys - Remove jq package.json mutation, use pnpm exec directly - Add separate generate step for GraphQL types - Fix env vars to CATALYST_* namespace for CLI commands - Remove --framework flag (removed in alpha) - Add --prebuilt to deploy (skip redundant build) - Add BIGCOMMERCE_API_HOST for integration API --------- Co-authored-by: Matthew Volk --- .github/workflows/native-hosting.yml | 73 ++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/native-hosting.yml diff --git a/.github/workflows/native-hosting.yml b/.github/workflows/native-hosting.yml new file mode 100644 index 0000000000..456db9b4d4 --- /dev/null +++ b/.github/workflows/native-hosting.yml @@ -0,0 +1,73 @@ +name: Native Hosting + +on: + push: + branches: [canary] + +jobs: + build-and-deploy: + name: Build and Deploy + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v3 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Install Catalyst CLI + run: pnpm add @bigcommerce/catalyst@alpha @opennextjs/cloudflare@1.17.3 + working-directory: core + + - name: Convert proxy.ts to middleware.ts + working-directory: core + run: | + mv proxy.ts middleware.ts + sed -i 's/export const proxy/export const middleware/' middleware.ts + sed -i "s/export const config = {/export const config = {\n runtime: 'experimental-edge',/" middleware.ts + + - name: Build monorepo packages + run: pnpm --filter "./packages/*" build + + - name: Generate GraphQL types + run: pnpm run generate + working-directory: core + env: + BIGCOMMERCE_STORE_HASH: ${{ vars.NATIVE_HOSTING_BIGCOMMERCE_STORE_HASH }} + BIGCOMMERCE_STOREFRONT_TOKEN: ${{ secrets.NATIVE_HOSTING_BIGCOMMERCE_STOREFRONT_TOKEN }} + BIGCOMMERCE_CHANNEL_ID: ${{ vars.NATIVE_HOSTING_BIGCOMMERCE_CHANNEL_ID }} + + - name: Build + run: pnpm exec catalyst build + working-directory: core + env: + # CLI env vars + CATALYST_PROJECT_UUID: ${{ secrets.NATIVE_HOSTING_BIGCOMMERCE_PROJECT_UUID }} + # App env vars (needed by Next.js build for GraphQL calls in next.config.ts) + BIGCOMMERCE_STORE_HASH: ${{ vars.NATIVE_HOSTING_BIGCOMMERCE_STORE_HASH }} + BIGCOMMERCE_STOREFRONT_TOKEN: ${{ secrets.NATIVE_HOSTING_BIGCOMMERCE_STOREFRONT_TOKEN }} + BIGCOMMERCE_CHANNEL_ID: ${{ vars.NATIVE_HOSTING_BIGCOMMERCE_CHANNEL_ID }} + AUTH_SECRET: ${{ secrets.NATIVE_HOSTING_AUTH_SECRET }} + + - name: Deploy + run: | + pnpm exec catalyst deploy --prebuilt \ + --secret BIGCOMMERCE_STORE_HASH=${{ vars.NATIVE_HOSTING_BIGCOMMERCE_STORE_HASH }} \ + --secret BIGCOMMERCE_STOREFRONT_TOKEN=${{ secrets.NATIVE_HOSTING_BIGCOMMERCE_STOREFRONT_TOKEN }} \ + --secret BIGCOMMERCE_CHANNEL_ID=${{ vars.NATIVE_HOSTING_BIGCOMMERCE_CHANNEL_ID }} \ + --secret AUTH_SECRET=${{ secrets.NATIVE_HOSTING_AUTH_SECRET }} + working-directory: core + env: + CATALYST_STORE_HASH: ${{ vars.NATIVE_HOSTING_BIGCOMMERCE_STORE_HASH }} + CATALYST_ACCESS_TOKEN: ${{ secrets.NATIVE_HOSTING_BIGCOMMERCE_ACCESS_TOKEN }} + CATALYST_PROJECT_UUID: ${{ secrets.NATIVE_HOSTING_BIGCOMMERCE_PROJECT_UUID }} From a8dd99ef9a1aeab3341e14d39137085cd67f1673 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Wed, 1 Apr 2026 11:47:34 -0600 Subject: [PATCH 21/47] fix(core): render hidden fields in DynamicForm to prevent NaN pageEntityId (#2963) The DynamicFormField switch statement had no case for 'hidden' field types, causing hidden inputs (pageId, pagePath) to never render in the DOM. On form submission, these missing values produced undefined, which Number() converted to NaN, failing Zod validation. Refs: TRAC-292 Co-authored-by: Claude Opus 4.6 (1M context) --- .changeset/fix-hidden-fields-d35665be.md | 5 +++++ core/vibes/soul/form/dynamic-form/index.tsx | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 .changeset/fix-hidden-fields-d35665be.md diff --git a/.changeset/fix-hidden-fields-d35665be.md b/.changeset/fix-hidden-fields-d35665be.md new file mode 100644 index 0000000000..e009899f63 --- /dev/null +++ b/.changeset/fix-hidden-fields-d35665be.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Fix DynamicForm not rendering hidden field types, which caused `pageEntityId` to be `NaN` on contact form submission. diff --git a/core/vibes/soul/form/dynamic-form/index.tsx b/core/vibes/soul/form/dynamic-form/index.tsx index 706d67a507..65321d0e51 100644 --- a/core/vibes/soul/form/dynamic-form/index.tsx +++ b/core/vibes/soul/form/dynamic-form/index.tsx @@ -449,5 +449,8 @@ function DynamicFormField({ selected={typeof controls.value === 'string' ? new Date(controls.value) : undefined} /> ); + + case 'hidden': + return ; } } From a85fa42aaa89ae6c2ac5e69b43d4c0bf15dacdf9 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 14 Apr 2026 13:50:33 -0500 Subject: [PATCH 22/47] feat(core): add X-Correlation-ID header to all GraphQL requests (#2976) * feat(core): add X-Correlation-ID header to all GraphQL requests Each page render gets a stable UUID (via React.cache) that persists across all fetches within the same render, enabling easier request tracing in server logs. Co-Authored-By: Claude Opus 4.6 (1M context) * fix(core): wrap correlation-id import in try/catch for config resolution The dynamic import of correlation-id.ts fails during next.config.ts resolution because React.cache is unavailable in that context. Wrap in try/catch to match the existing pattern for next-intl/server. Co-Authored-By: Claude Opus 4.6 (1M context) * chore: change correlation-id changeset to patch Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .changeset/correlation-id-header.md | 5 +++++ core/client/correlation-id.ts | 3 +++ core/client/index.ts | 8 ++++++++ 3 files changed, 16 insertions(+) create mode 100644 .changeset/correlation-id-header.md create mode 100644 core/client/correlation-id.ts diff --git a/.changeset/correlation-id-header.md b/.changeset/correlation-id-header.md new file mode 100644 index 0000000000..a91ea05ecc --- /dev/null +++ b/.changeset/correlation-id-header.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Add X-Correlation-ID header to all GraphQL requests. Each page render gets a stable UUID that persists across all fetches within the same render, enabling easier request tracing in server logs. diff --git a/core/client/correlation-id.ts b/core/client/correlation-id.ts new file mode 100644 index 0000000000..b6c5073169 --- /dev/null +++ b/core/client/correlation-id.ts @@ -0,0 +1,3 @@ +import { cache } from 'react'; + +export const getCorrelationId = cache(() => crypto.randomUUID()); diff --git a/core/client/index.ts b/core/client/index.ts index d14bcb463b..63db24e2ab 100644 --- a/core/client/index.ts +++ b/core/client/index.ts @@ -52,6 +52,14 @@ export const client = createClient({ const requestHeaders: Record = {}; const locale = await getLocale(); + try { + const { getCorrelationId } = await import('./correlation-id'); + + requestHeaders['X-Correlation-ID'] = getCorrelationId(); + } catch { + // correlation-id imports React.cache which is unavailable during next.config.ts resolution + } + if (fetchOptions?.cache && ['no-store', 'no-cache'].includes(fetchOptions.cache)) { const { headers } = await import('next/headers'); const ipAddress = (await headers()).get('X-Forwarded-For'); From be980dace0fa89307ba7461d57cd8f2f3fe5fadc Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 14 Apr 2026 18:13:33 -0500 Subject: [PATCH 23/47] fix: exclude /brands path and add PLP brands sampling to unlighthouse config (#2983) Co-authored-by: Claude Opus 4.6 (1M context) --- unlighthouse.config.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/unlighthouse.config.ts b/unlighthouse.config.ts index 796466a4c9..aff1be9269 100644 --- a/unlighthouse.config.ts +++ b/unlighthouse.config.ts @@ -26,12 +26,16 @@ export default { "/early-access/*/*", "/digital-test-product/", "/blog/\\?tag=*", + "/brands/", ], customSampling: { "/smith-journal-13/|/dustpan-brush/|/utility-caddy/|/canvas-laundry-cart/|/laundry-detergent/|/tiered-wire-basket/|/oak-cheese-grater/|/1-l-le-parfait-jar/|/chemex-coffeemaker-3-cup/|/sample-able-brewing-system/|/orbit-terrarium-small/|/orbit-terrarium-large/|/fog-linen-chambray-towel-beige-stripe/|/zz-plant/": { name: "PDP" }, "/shop-all/|/bath/|/garden/|/kitchen/|/publications/|/early-access/": { - name: "PLP", + name: "PLP categories", + }, + "/brands/sagaform/|/brands/ofs/|/brands/common-good/": { + name: "PLP brands", }, }, // Disable throttling to avoid issues with cold start and cold cache. From 225c4ef4ddabb66f005475a20cdb4d4e85dd0f3f Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Thu, 23 Apr 2026 18:00:32 -0500 Subject: [PATCH 24/47] test(cli): make path assertions OS-agnostic (#2990) The spec files for the `build`, `dev`, and `start` CLI commands asserted that execa was called with `'node_modules/.bin/next'` (and `'.bigcommerce/wrangler.jsonc'` in the OpenNext case) using POSIX separators. Production code builds these paths via Node's `path.join`, which returns `\`-separated paths on Windows, so the assertions fail on `CLI Tests (windows-latest)`. Import `join` in each spec and build the expected path the same way the production code does, so the assertions match regardless of OS. Fixes LTRAC-594 Co-authored-by: Claude --- packages/catalyst/src/cli/commands/build.spec.ts | 3 ++- packages/catalyst/src/cli/commands/dev.spec.ts | 3 ++- packages/catalyst/src/cli/commands/start.spec.ts | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/catalyst/src/cli/commands/build.spec.ts b/packages/catalyst/src/cli/commands/build.spec.ts index 071bb86191..06f5525693 100644 --- a/packages/catalyst/src/cli/commands/build.spec.ts +++ b/packages/catalyst/src/cli/commands/build.spec.ts @@ -1,5 +1,6 @@ import { Command } from 'commander'; import { execa } from 'execa'; +import { join } from 'node:path'; import { expect, test, vi } from 'vitest'; import { program } from '../program'; @@ -33,7 +34,7 @@ test('calls execa with Next.js build if framework is nextjs', async () => { await program.parseAsync(['node', 'catalyst', 'build', '--framework', 'nextjs', '--debug']); expect(execa).toHaveBeenCalledWith( - 'node_modules/.bin/next', + join('node_modules', '.bin', 'next'), ['build', '--debug'], expect.objectContaining({ stdio: 'inherit', diff --git a/packages/catalyst/src/cli/commands/dev.spec.ts b/packages/catalyst/src/cli/commands/dev.spec.ts index 9c1283983d..17ce28951d 100644 --- a/packages/catalyst/src/cli/commands/dev.spec.ts +++ b/packages/catalyst/src/cli/commands/dev.spec.ts @@ -1,5 +1,6 @@ import { Command } from 'commander'; import { execa } from 'execa'; +import { join } from 'node:path'; import { expect, test, vi } from 'vitest'; import { program } from '../program'; @@ -25,7 +26,7 @@ test('calls execa with Next.js development server', async () => { await program.parseAsync(['node', 'catalyst', 'dev', '-p', '3001']); expect(execa).toHaveBeenCalledWith( - 'node_modules/.bin/next', + join('node_modules', '.bin', 'next'), ['dev', '-p', '3001'], expect.objectContaining({ stdio: 'inherit', diff --git a/packages/catalyst/src/cli/commands/start.spec.ts b/packages/catalyst/src/cli/commands/start.spec.ts index 3cfe08d2ad..6a28be025a 100644 --- a/packages/catalyst/src/cli/commands/start.spec.ts +++ b/packages/catalyst/src/cli/commands/start.spec.ts @@ -1,5 +1,6 @@ import { Command } from 'commander'; import { execa } from 'execa'; +import { join } from 'node:path'; import { afterEach, beforeAll, beforeEach, expect, test, vi } from 'vitest'; import { consola } from '../lib/logger'; @@ -66,7 +67,7 @@ test('calls execa with Next.js production optimized server', async () => { ]); expect(execa).toHaveBeenCalledWith( - 'node_modules/.bin/next', + join('node_modules', '.bin', 'next'), ['start', '--port', '3001'], expect.objectContaining({ stdio: 'inherit', @@ -93,7 +94,7 @@ test('calls execa with OpenNext production optimized server', async () => { 'opennextjs-cloudflare', 'preview', '--config', - '.bigcommerce/wrangler.jsonc', + join('.bigcommerce', 'wrangler.jsonc'), '--port', '3001', ], From 518d20a8a8d59bfb45384acee72e04f5366daca8 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Fri, 24 Apr 2026 10:40:32 -0500 Subject: [PATCH 25/47] fix(core): restore locale-aware lang attribute on html (#2989) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The root tag was hardcoded to lang="en" for all locales because a new root app/layout.tsx to enable the branded /404 page. That fix solved the 404 but regressed the lang attribute. Adopt next-intl's documented pattern: - app/layout.tsx is now a passthrough (returns children) — required by Next.js but owns no markup. - app/[locale]/layout.tsx owns and again, so localized pages get the correct language. - app/not-found.tsx owns its own /, fonts, and global CSS so the branded 404 still renders for non-localized requests. Verified parity with canary on runtime 404 behavior (both serve the Next.js error-fallback shell for dynamic 404s) and clean output in the prerendered _not-found.html static file. Fixes LTRAC-578 LTRAC-578: chore - Bump changeset to minor Restructures / ownership across root layout, [locale] layout, and not-found — customers who customized these files will need to migrate, so a minor bump is more appropriate than patch. Refs LTRAC-578 LTRAC-578: docs - Add TODO for rootParams migration Note that the passthrough root layout is a workaround — once Next.js `rootParams` (16.2+) is available on Native Hosting, we should move / back here and derive `lang` from rootParams. Refs LTRAC-578 Co-authored-by: Claude --- .changeset/fix-html-lang-locale.md | 5 +++ core/app/[locale]/layout.tsx | 58 ++++++++++++++++-------------- core/app/layout.tsx | 17 ++++----- core/app/not-found.tsx | 49 +++++++++++++++---------- 4 files changed, 75 insertions(+), 54 deletions(-) create mode 100644 .changeset/fix-html-lang-locale.md diff --git a/.changeset/fix-html-lang-locale.md b/.changeset/fix-html-lang-locale.md new file mode 100644 index 0000000000..9f682ebe14 --- /dev/null +++ b/.changeset/fix-html-lang-locale.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": minor +--- + +Restore locale-aware `lang` attribute on the root `` tag. The previous root layout hardcoded `lang="en"` for all locales; ownership of ``/`` now lives in `app/[locale]/layout.tsx` so `lang={locale}` reflects the active locale. The root `app/layout.tsx` is now a passthrough, and `app/not-found.tsx` is self-sufficient (renders its own ``/``) to preserve the branded 404 for non-localized requests. diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index 11d3d88e85..f0a08d7f3f 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -1,5 +1,6 @@ import { Analytics } from '@vercel/analytics/react'; import { SpeedInsights } from '@vercel/speed-insights/next'; +import { clsx } from 'clsx'; import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { NextIntlClientProvider } from 'next-intl'; @@ -7,6 +8,9 @@ import { setRequestLocale } from 'next-intl/server'; import { NuqsAdapter } from 'nuqs/adapters/next/app'; import { cache, PropsWithChildren } from 'react'; +import '../../globals.css'; + +import { fonts } from '~/app/fonts'; import { CookieNotifications } from '~/app/notifications'; import { Providers } from '~/app/providers'; import { client } from '~/client'; @@ -136,32 +140,34 @@ export default async function RootLayout({ params, children }: Props) { const privacyPolicyUrl = rootData.data.site.settings?.privacy?.privacyPolicyUrl; return ( - <> - - - - - - {toastNotificationCookieData && ( - - )} - {children} - - - - - - - - + f.variable))} lang={locale}> + + + + + + + {toastNotificationCookieData && ( + + )} + {children} + + + + + + + + + ); } diff --git a/core/app/layout.tsx b/core/app/layout.tsx index ea754b0fb4..fbe79356c3 100644 --- a/core/app/layout.tsx +++ b/core/app/layout.tsx @@ -1,14 +1,11 @@ -import { clsx } from 'clsx'; import { PropsWithChildren } from 'react'; -import '../globals.css'; - -import { fonts } from '~/app/fonts'; - +// Since we have a `not-found.tsx` at the root, a layout file is required even if +// it just passes children through. Ownership of / lives in +// app/[locale]/layout.tsx (to set lang={locale}) and app/not-found.tsx (for +// non-localized 404s). See: https://next-intl.dev/docs/environments/error-files +// TODO: Move / back here and set lang via Next.js `rootParams` +// once it is available on Native Hosting (Next.js 16.2+). export default function RootLayout({ children }: PropsWithChildren) { - return ( - f.variable))} lang="en"> - {children} - - ); + return children; } diff --git a/core/app/not-found.tsx b/core/app/not-found.tsx index 8651b7547c..9852d7804a 100644 --- a/core/app/not-found.tsx +++ b/core/app/not-found.tsx @@ -1,22 +1,35 @@ +import { clsx } from 'clsx'; + +import '../globals.css'; + +import { fonts } from '~/app/fonts'; + +// Renders for non-localized requests that don't match any route (e.g. /unknown.txt) +// or when app/[locale]/layout.tsx calls notFound() for an invalid locale. Since +// app/layout.tsx is a passthrough, this page must own its own /. export default function RootNotFound() { return ( -
-
-
-

- Not found -

-

- The page you are looking for could not be found. -

- - Go to homepage - -
-
-
+ f.variable))} lang="en"> + +
+
+
+

+ Not found +

+

+ The page you are looking for could not be found. +

+ + Go to homepage + +
+
+
+ + ); } From e18feb6dd4a02526e239ff0cf7e839882fc50814 Mon Sep 17 00:00:00 2001 From: bc-svc-local <102379007+bc-svc-local@users.noreply.github.com> Date: Fri, 24 Apr 2026 18:06:39 +0200 Subject: [PATCH 26/47] Update translations (#2987) * feat(other): LOCAL-1444 delivery translation * chore(core): create translations patch --------- Co-authored-by: bc-svc-local --- .changeset/translations-patch-e3d3b994.md | 5 +++++ core/messages/es-419.json | 12 ++++++------ core/messages/es-AR.json | 12 ++++++------ core/messages/es-CL.json | 12 ++++++------ core/messages/es-CO.json | 12 ++++++------ core/messages/es-LA.json | 12 ++++++------ core/messages/es-MX.json | 12 ++++++------ core/messages/es-PE.json | 12 ++++++------ core/messages/no.json | 2 +- core/messages/sv.json | 2 +- 10 files changed, 49 insertions(+), 44 deletions(-) create mode 100644 .changeset/translations-patch-e3d3b994.md diff --git a/.changeset/translations-patch-e3d3b994.md b/.changeset/translations-patch-e3d3b994.md new file mode 100644 index 0000000000..ad17b2636a --- /dev/null +++ b/.changeset/translations-patch-e3d3b994.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Update translations. diff --git a/core/messages/es-419.json b/core/messages/es-419.json index f5e29ab304..e95b645b4c 100644 --- a/core/messages/es-419.json +++ b/core/messages/es-419.json @@ -138,7 +138,7 @@ "searchResults": "Resultados de búsqueda para", "subCategories": "Categorías", "Breadcrumbs": { - "home": "Página de inicio", + "home": "Inicio", "search": "Buscar" }, "Empty": { @@ -348,7 +348,7 @@ }, "Blog": { "title": "Blog", - "home": "Página de inicio", + "home": "Inicio", "Empty": { "title": "No se encontraron publicaciones de blog", "subtitle": "Vuelve a consultar más tarde para obtener más contenido" @@ -522,10 +522,10 @@ }, "WebPages": { "Normal": { - "home": "Página de inicio" + "home": "Inicio" }, "ContactUs": { - "home": "Página de inicio", + "home": "Inicio", "Form": { "success": "Gracias por ponerte en contacto. Nos comunicaremos contigo pronto.", "successCta": "Seguir comprando", @@ -560,7 +560,7 @@ }, "Components": { "Header": { - "home": "Página de inicio", + "home": "Inicio", "toggleNavigation": "Alternar navegación", "Icons": { "account": "Perfil", @@ -585,7 +585,7 @@ } }, "Footer": { - "home": "Página de inicio", + "home": "Inicio", "contactUs": "Contacto", "socialMediaLinks": "Enlaces a redes sociales", "categories": "Categorías", diff --git a/core/messages/es-AR.json b/core/messages/es-AR.json index f5e29ab304..e95b645b4c 100644 --- a/core/messages/es-AR.json +++ b/core/messages/es-AR.json @@ -138,7 +138,7 @@ "searchResults": "Resultados de búsqueda para", "subCategories": "Categorías", "Breadcrumbs": { - "home": "Página de inicio", + "home": "Inicio", "search": "Buscar" }, "Empty": { @@ -348,7 +348,7 @@ }, "Blog": { "title": "Blog", - "home": "Página de inicio", + "home": "Inicio", "Empty": { "title": "No se encontraron publicaciones de blog", "subtitle": "Vuelve a consultar más tarde para obtener más contenido" @@ -522,10 +522,10 @@ }, "WebPages": { "Normal": { - "home": "Página de inicio" + "home": "Inicio" }, "ContactUs": { - "home": "Página de inicio", + "home": "Inicio", "Form": { "success": "Gracias por ponerte en contacto. Nos comunicaremos contigo pronto.", "successCta": "Seguir comprando", @@ -560,7 +560,7 @@ }, "Components": { "Header": { - "home": "Página de inicio", + "home": "Inicio", "toggleNavigation": "Alternar navegación", "Icons": { "account": "Perfil", @@ -585,7 +585,7 @@ } }, "Footer": { - "home": "Página de inicio", + "home": "Inicio", "contactUs": "Contacto", "socialMediaLinks": "Enlaces a redes sociales", "categories": "Categorías", diff --git a/core/messages/es-CL.json b/core/messages/es-CL.json index f5e29ab304..e95b645b4c 100644 --- a/core/messages/es-CL.json +++ b/core/messages/es-CL.json @@ -138,7 +138,7 @@ "searchResults": "Resultados de búsqueda para", "subCategories": "Categorías", "Breadcrumbs": { - "home": "Página de inicio", + "home": "Inicio", "search": "Buscar" }, "Empty": { @@ -348,7 +348,7 @@ }, "Blog": { "title": "Blog", - "home": "Página de inicio", + "home": "Inicio", "Empty": { "title": "No se encontraron publicaciones de blog", "subtitle": "Vuelve a consultar más tarde para obtener más contenido" @@ -522,10 +522,10 @@ }, "WebPages": { "Normal": { - "home": "Página de inicio" + "home": "Inicio" }, "ContactUs": { - "home": "Página de inicio", + "home": "Inicio", "Form": { "success": "Gracias por ponerte en contacto. Nos comunicaremos contigo pronto.", "successCta": "Seguir comprando", @@ -560,7 +560,7 @@ }, "Components": { "Header": { - "home": "Página de inicio", + "home": "Inicio", "toggleNavigation": "Alternar navegación", "Icons": { "account": "Perfil", @@ -585,7 +585,7 @@ } }, "Footer": { - "home": "Página de inicio", + "home": "Inicio", "contactUs": "Contacto", "socialMediaLinks": "Enlaces a redes sociales", "categories": "Categorías", diff --git a/core/messages/es-CO.json b/core/messages/es-CO.json index f5e29ab304..e95b645b4c 100644 --- a/core/messages/es-CO.json +++ b/core/messages/es-CO.json @@ -138,7 +138,7 @@ "searchResults": "Resultados de búsqueda para", "subCategories": "Categorías", "Breadcrumbs": { - "home": "Página de inicio", + "home": "Inicio", "search": "Buscar" }, "Empty": { @@ -348,7 +348,7 @@ }, "Blog": { "title": "Blog", - "home": "Página de inicio", + "home": "Inicio", "Empty": { "title": "No se encontraron publicaciones de blog", "subtitle": "Vuelve a consultar más tarde para obtener más contenido" @@ -522,10 +522,10 @@ }, "WebPages": { "Normal": { - "home": "Página de inicio" + "home": "Inicio" }, "ContactUs": { - "home": "Página de inicio", + "home": "Inicio", "Form": { "success": "Gracias por ponerte en contacto. Nos comunicaremos contigo pronto.", "successCta": "Seguir comprando", @@ -560,7 +560,7 @@ }, "Components": { "Header": { - "home": "Página de inicio", + "home": "Inicio", "toggleNavigation": "Alternar navegación", "Icons": { "account": "Perfil", @@ -585,7 +585,7 @@ } }, "Footer": { - "home": "Página de inicio", + "home": "Inicio", "contactUs": "Contacto", "socialMediaLinks": "Enlaces a redes sociales", "categories": "Categorías", diff --git a/core/messages/es-LA.json b/core/messages/es-LA.json index f5e29ab304..e95b645b4c 100644 --- a/core/messages/es-LA.json +++ b/core/messages/es-LA.json @@ -138,7 +138,7 @@ "searchResults": "Resultados de búsqueda para", "subCategories": "Categorías", "Breadcrumbs": { - "home": "Página de inicio", + "home": "Inicio", "search": "Buscar" }, "Empty": { @@ -348,7 +348,7 @@ }, "Blog": { "title": "Blog", - "home": "Página de inicio", + "home": "Inicio", "Empty": { "title": "No se encontraron publicaciones de blog", "subtitle": "Vuelve a consultar más tarde para obtener más contenido" @@ -522,10 +522,10 @@ }, "WebPages": { "Normal": { - "home": "Página de inicio" + "home": "Inicio" }, "ContactUs": { - "home": "Página de inicio", + "home": "Inicio", "Form": { "success": "Gracias por ponerte en contacto. Nos comunicaremos contigo pronto.", "successCta": "Seguir comprando", @@ -560,7 +560,7 @@ }, "Components": { "Header": { - "home": "Página de inicio", + "home": "Inicio", "toggleNavigation": "Alternar navegación", "Icons": { "account": "Perfil", @@ -585,7 +585,7 @@ } }, "Footer": { - "home": "Página de inicio", + "home": "Inicio", "contactUs": "Contacto", "socialMediaLinks": "Enlaces a redes sociales", "categories": "Categorías", diff --git a/core/messages/es-MX.json b/core/messages/es-MX.json index f5e29ab304..e95b645b4c 100644 --- a/core/messages/es-MX.json +++ b/core/messages/es-MX.json @@ -138,7 +138,7 @@ "searchResults": "Resultados de búsqueda para", "subCategories": "Categorías", "Breadcrumbs": { - "home": "Página de inicio", + "home": "Inicio", "search": "Buscar" }, "Empty": { @@ -348,7 +348,7 @@ }, "Blog": { "title": "Blog", - "home": "Página de inicio", + "home": "Inicio", "Empty": { "title": "No se encontraron publicaciones de blog", "subtitle": "Vuelve a consultar más tarde para obtener más contenido" @@ -522,10 +522,10 @@ }, "WebPages": { "Normal": { - "home": "Página de inicio" + "home": "Inicio" }, "ContactUs": { - "home": "Página de inicio", + "home": "Inicio", "Form": { "success": "Gracias por ponerte en contacto. Nos comunicaremos contigo pronto.", "successCta": "Seguir comprando", @@ -560,7 +560,7 @@ }, "Components": { "Header": { - "home": "Página de inicio", + "home": "Inicio", "toggleNavigation": "Alternar navegación", "Icons": { "account": "Perfil", @@ -585,7 +585,7 @@ } }, "Footer": { - "home": "Página de inicio", + "home": "Inicio", "contactUs": "Contacto", "socialMediaLinks": "Enlaces a redes sociales", "categories": "Categorías", diff --git a/core/messages/es-PE.json b/core/messages/es-PE.json index f5e29ab304..e95b645b4c 100644 --- a/core/messages/es-PE.json +++ b/core/messages/es-PE.json @@ -138,7 +138,7 @@ "searchResults": "Resultados de búsqueda para", "subCategories": "Categorías", "Breadcrumbs": { - "home": "Página de inicio", + "home": "Inicio", "search": "Buscar" }, "Empty": { @@ -348,7 +348,7 @@ }, "Blog": { "title": "Blog", - "home": "Página de inicio", + "home": "Inicio", "Empty": { "title": "No se encontraron publicaciones de blog", "subtitle": "Vuelve a consultar más tarde para obtener más contenido" @@ -522,10 +522,10 @@ }, "WebPages": { "Normal": { - "home": "Página de inicio" + "home": "Inicio" }, "ContactUs": { - "home": "Página de inicio", + "home": "Inicio", "Form": { "success": "Gracias por ponerte en contacto. Nos comunicaremos contigo pronto.", "successCta": "Seguir comprando", @@ -560,7 +560,7 @@ }, "Components": { "Header": { - "home": "Página de inicio", + "home": "Inicio", "toggleNavigation": "Alternar navegación", "Icons": { "account": "Perfil", @@ -585,7 +585,7 @@ } }, "Footer": { - "home": "Página de inicio", + "home": "Inicio", "contactUs": "Contacto", "socialMediaLinks": "Enlaces a redes sociales", "categories": "Categorías", diff --git a/core/messages/no.json b/core/messages/no.json index dc74691519..8425c93b25 100644 --- a/core/messages/no.json +++ b/core/messages/no.json @@ -465,7 +465,7 @@ "currentStock": "{antall, nummer} på lager", "backorderQuantity": "{antall, nummer} vil være restordre", "loadingMoreImages": "Laster inn flere bilder", - "imagesLoaded": "{antall, flertall, =1 {1 bilde til ble lastet inn} other {# flere bilder ble lastet inn}}", + "imagesLoaded": "{count, plural, =1 {1 bilde til ble lastet inn} other {# flere bilder ble lastet inn}}", "Submit": { "addToCart": "Legg i handlekurv", "outOfStock": "Utsolgt", diff --git a/core/messages/sv.json b/core/messages/sv.json index 7fc883ce72..928de31f92 100644 --- a/core/messages/sv.json +++ b/core/messages/sv.json @@ -205,7 +205,7 @@ "shipping": "Frakt", "tax": "Beskatta", "orderSummary": "Beställningssammanfattning", - "paymentMethodsLabel": "{antal, plural, =1 {Betalningsmetod} other {Betalningsmetoder}}", + "paymentMethodsLabel": "{count, plural, =1 {Betalningsmetod} other {Betalningsmetoder}}", "paymentEndingInLabel": "Slutar på", "PaymentMethods": { "creditCard": "Kreditkort", From 9dff9d84164d3c6b9c51ef5d37b94a580fc74d53 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Fri, 24 Apr 2026 16:54:08 -0500 Subject: [PATCH 27/47] fix(makeswift): move MakeswiftProvider into locale layout, pass locale Addresses review feedback on #2991: `MakeswiftProvider` needs the active `locale` (per Makeswift ReactRuntimeProvider docs), so move the provider into `app/[locale]/layout.tsx` where `locale` is available and forward it through. Root `app/layout.tsx` stays as canary's pass-through. The 404 page (`app/not-found.tsx`) wraps its own tree with `MakeswiftProvider` + `` explicitly so the branded theme still applies outside `[locale]`. Co-Authored-By: Claude Opus 4.7 (1M context) --- core/app/[locale]/layout.tsx | 67 +++++++++++++++++++-------------- core/app/layout.tsx | 17 +-------- core/app/not-found.tsx | 58 +++++++++++++++++----------- core/lib/makeswift/provider.tsx | 3 ++ 4 files changed, 79 insertions(+), 66 deletions(-) diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index f0a08d7f3f..e127053414 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -1,3 +1,4 @@ +import { getSiteVersion } from '@makeswift/runtime/next/server'; import { Analytics } from '@vercel/analytics/react'; import { SpeedInsights } from '@vercel/speed-insights/next'; import { clsx } from 'clsx'; @@ -23,8 +24,12 @@ import { ScriptsFragment } from '~/components/consent-manager/scripts-fragment'; import { ContainerQueryPolyfill } from '~/components/polyfills/container-query'; import { scriptsTransformer } from '~/data-transformers/scripts-transformer'; import { routing } from '~/i18n/routing'; +import { SiteTheme } from '~/lib/makeswift/components/site-theme'; +import { MakeswiftProvider } from '~/lib/makeswift/provider'; import { getToastNotification } from '~/lib/server-toast'; +import '~/lib/makeswift/components'; + const RootLayoutMetadataQuery = graphql( ` query RootLayoutMetadataQuery { @@ -125,6 +130,7 @@ export default async function RootLayout({ params, children }: Props) { const rootData = await fetchRootLayoutMetadata(); const toastNotificationCookieData = await getToastNotification(); + const siteVersion = await getSiteVersion(); if (!routing.locales.includes(locale)) { notFound(); @@ -140,34 +146,39 @@ export default async function RootLayout({ params, children }: Props) { const privacyPolicyUrl = rootData.data.site.settings?.privacy?.privacyPolicyUrl; return ( - f.variable))} lang={locale}> - - - - - - - {toastNotificationCookieData && ( - - )} - {children} - - - - - - - - - + + f.variable))} lang={locale}> + + + + + + + + + + {toastNotificationCookieData && ( + + )} + {children} + + + + + + + + + + ); } diff --git a/core/app/layout.tsx b/core/app/layout.tsx index 7617565fb5..fbe79356c3 100644 --- a/core/app/layout.tsx +++ b/core/app/layout.tsx @@ -1,24 +1,11 @@ -import { getSiteVersion } from '@makeswift/runtime/next/server'; import { PropsWithChildren } from 'react'; -import { SiteTheme } from '~/lib/makeswift/components/site-theme'; -import { MakeswiftProvider } from '~/lib/makeswift/provider'; - -import '~/lib/makeswift/components'; - // Since we have a `not-found.tsx` at the root, a layout file is required even if // it just passes children through. Ownership of / lives in // app/[locale]/layout.tsx (to set lang={locale}) and app/not-found.tsx (for // non-localized 404s). See: https://next-intl.dev/docs/environments/error-files // TODO: Move / back here and set lang via Next.js `rootParams` // once it is available on Native Hosting (Next.js 16.2+). -export default async function RootLayout({ children }: PropsWithChildren) { - const siteVersion = await getSiteVersion(); - - return ( - - - {children} - - ); +export default function RootLayout({ children }: PropsWithChildren) { + return children; } diff --git a/core/app/not-found.tsx b/core/app/not-found.tsx index 9852d7804a..ee55000c5d 100644 --- a/core/app/not-found.tsx +++ b/core/app/not-found.tsx @@ -1,35 +1,47 @@ +import { getSiteVersion } from '@makeswift/runtime/next/server'; import { clsx } from 'clsx'; import '../globals.css'; import { fonts } from '~/app/fonts'; +import { SiteTheme } from '~/lib/makeswift/components/site-theme'; +import { MakeswiftProvider } from '~/lib/makeswift/provider'; + +import '~/lib/makeswift/components'; // Renders for non-localized requests that don't match any route (e.g. /unknown.txt) // or when app/[locale]/layout.tsx calls notFound() for an invalid locale. Since // app/layout.tsx is a passthrough, this page must own its own /. -export default function RootNotFound() { +export default async function RootNotFound() { + const siteVersion = await getSiteVersion(); + return ( - f.variable))} lang="en"> - -
-
-
-

- Not found -

-

- The page you are looking for could not be found. -

- - Go to homepage - -
-
-
- - + + f.variable))} lang="en"> + + + + +
+
+
+

+ Not found +

+

+ The page you are looking for could not be found. +

+ + Go to homepage + +
+
+
+ + +
); } diff --git a/core/lib/makeswift/provider.tsx b/core/lib/makeswift/provider.tsx index 8377ff9443..3cb8c18686 100644 --- a/core/lib/makeswift/provider.tsx +++ b/core/lib/makeswift/provider.tsx @@ -7,15 +7,18 @@ import '~/lib/makeswift/components'; export function MakeswiftProvider({ children, + locale, siteVersion, }: { children: React.ReactNode; + locale?: string; siteVersion: SiteVersion | null; }) { return ( From ed7622453edc667a3582646074e0ccb72eb7b714 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Mon, 27 Apr 2026 14:31:26 -0600 Subject: [PATCH 28/47] fix: update create-catalyst client id (#2993) --- .changeset/hip-ways-complain.md | 5 +++++ packages/create-catalyst/src/utils/auth.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/hip-ways-complain.md diff --git a/.changeset/hip-ways-complain.md b/.changeset/hip-ways-complain.md new file mode 100644 index 0000000000..596a2dd77c --- /dev/null +++ b/.changeset/hip-ways-complain.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/create-catalyst": patch +--- + +Update the client id to the new one. diff --git a/packages/create-catalyst/src/utils/auth.ts b/packages/create-catalyst/src/utils/auth.ts index 1134ed36b1..c43bc05449 100644 --- a/packages/create-catalyst/src/utils/auth.ts +++ b/packages/create-catalyst/src/utils/auth.ts @@ -9,7 +9,7 @@ interface AuthConfig { export class Auth { private client: Https; - private readonly DEVICE_OAUTH_CLIENT_ID = 's1q4io7mah2lm1i6uwp9yl1eit80n3b'; + private readonly DEVICE_OAUTH_CLIENT_ID = 'b8063bu6hhml4e0lqh22yut63atsbyv'; constructor({ baseUrl }: AuthConfig) { this.client = new Https({ baseUrl }); From 9f119837064288b57ee50c9ca0de6093879393a7 Mon Sep 17 00:00:00 2001 From: Parth Shah <48393781+parthshahp@users.noreply.github.com> Date: Tue, 28 Apr 2026 16:35:14 -0400 Subject: [PATCH 29/47] chore: remove dead links in readme and update old docs links to new docs (#2996) --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1dd8389dff..c3a4ef88d6 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ **Catalyst** is the composable, fully customizable headless commerce framework for [BigCommerce](https://www.bigcommerce.com/). Catalyst is built with [Next.js](https://nextjs.org/), uses our [React](https://react.dev/) storefront components, and is backed by the -[GraphQL Storefront API](https://developer.bigcommerce.com/docs/storefront/graphql). +[GraphQL Storefront API](https://docs.bigcommerce.com/developer/docs/storefront/guides/graphql-storefront-api/overview). By choosing Catalyst, you'll have a fully-functional storefront within a few seconds, and spend zero time on wiring up APIs or building SEO, Accessibility, and Performance-optimized ecommerce components you've probably written many @@ -30,9 +30,9 @@ times before. You can instead go straight to work building your brand and making

🚀 catalyst.dev • - 🤗 BigCommerce Developer Community • + 🤗 BigCommerce Developer Community💬 GitHub Discussions • - 💡 Docs in this repo + 💡 Documentation

![-----------------------------------------------------](https://storage.googleapis.com/bigcommerce-developers/images/catalyst_readme_hr.png) @@ -41,7 +41,7 @@ times before. You can instead go straight to work building your brand and making The easiest way to deploy your Catalyst Storefront is to use the [One-Click Catalyst App](http://login.bigcommerce.com/deep-links/app/53284) available in the BigCommerce App Marketplace. -Check out the [Catalyst.dev One-Click Catalyst Documentation](https://www.catalyst.dev/docs/getting-started) for more details. +Check out the [Commerce One-Click Catalyst Documentation](https://docs.bigcommerce.com/developer/docs/storefront/catalyst/getting-started/workflows/one-click-catalyst) for more details. ## Getting Started @@ -71,7 +71,6 @@ Learn more about Catalyst at [catalyst.dev](https://catalyst.dev). ## Resources -- [Catalyst Documentation](https://catalyst.dev/docs/) -- [GraphQL Storefront API Playground](https://developer.bigcommerce.com/graphql-storefront/playground) -- [GraphQL Storefront API Explorer](https://developer.bigcommerce.com/graphql-storefront/explorer) -- [BigCommerce DevDocs](https://developer.bigcommerce.com/docs/build) +- [Catalyst Documentation](https://docs.bigcommerce.com/developer/docs/storefront/catalyst/overview) +- [GraphQL Storefront API Playground](https://docs.bigcommerce.com/developer/docs/storefront/guides/graphql-storefront-api/overview#accessing-the-graphql-storefront-playground) +- [BigCommerce DevDocs](https://docs.bigcommerce.com/developer/docs/overview/quick-start) From 5b2dc08428529d3d75ef25317ca7afea882c9c97 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Thu, 30 Apr 2026 11:05:56 -0600 Subject: [PATCH 30/47] Version Packages (`canary`) --- .changeset/hip-ways-complain.md | 5 ----- packages/create-catalyst/CHANGELOG.md | 6 ++++++ packages/create-catalyst/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/hip-ways-complain.md diff --git a/.changeset/hip-ways-complain.md b/.changeset/hip-ways-complain.md deleted file mode 100644 index 596a2dd77c..0000000000 --- a/.changeset/hip-ways-complain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bigcommerce/create-catalyst": patch ---- - -Update the client id to the new one. diff --git a/packages/create-catalyst/CHANGELOG.md b/packages/create-catalyst/CHANGELOG.md index 41935d1509..3b2f3c7473 100644 --- a/packages/create-catalyst/CHANGELOG.md +++ b/packages/create-catalyst/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.3 + +### Patch Changes + +- [#2993](https://github.com/bigcommerce/catalyst/pull/2993) [`ed76224`](https://github.com/bigcommerce/catalyst/commit/ed7622453edc667a3582646074e0ccb72eb7b714) Thanks [@chanceaclark](https://github.com/chanceaclark)! - Update the client id to the new one. + ## 1.0.2 ### Patch Changes diff --git a/packages/create-catalyst/package.json b/packages/create-catalyst/package.json index e7156dbb8f..02b1357aaf 100644 --- a/packages/create-catalyst/package.json +++ b/packages/create-catalyst/package.json @@ -1,6 +1,6 @@ { "name": "@bigcommerce/create-catalyst", - "version": "1.0.2", + "version": "1.0.3", "repository": { "type": "git", "url": "https://github.com/bigcommerce/catalyst", From ec9293076e926b714d036d26d34ab24753b98b91 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Thu, 30 Apr 2026 15:07:35 -0600 Subject: [PATCH 31/47] chore: add release-catalyst-patch skill for isolated patch releases (#3000) Document the workflow for shipping a single Catalyst package patch ahead of the normal release cadence, without bundling it with other queued changesets in the open Version Packages PR. Quarantines other changesets, runs `changeset version` for the target, hands the publish + canary push back to the user, and creates the GitHub release manually since the bot's release flow only fires when CI itself publishes. Co-authored-by: Claude --- .../skills/release-catalyst-patch/SKILL.md | 233 ++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 .claude/skills/release-catalyst-patch/SKILL.md diff --git a/.claude/skills/release-catalyst-patch/SKILL.md b/.claude/skills/release-catalyst-patch/SKILL.md new file mode 100644 index 0000000000..ec489bb1de --- /dev/null +++ b/.claude/skills/release-catalyst-patch/SKILL.md @@ -0,0 +1,233 @@ +--- +name: release-catalyst-patch +description: > + Release a single Catalyst package patch in isolation, without bundling it with + other queued changesets in the open Version Packages PR. Use when the user says + "/release-catalyst-patch", "isolate a patch release", "publish only one package", + or wants to ship a single package's changeset ahead of the normal release cadence. + Performs the full flow locally (`changeset version`, build, `changeset publish`, + push, GitHub release) so the remaining queued changesets stay untouched in the + Version Packages PR. +--- + +# Release Catalyst Patch (single-package isolation) + +The Changesets GitHub Action picks one mode per push to `canary`: if any unconsumed +changesets exist, it opens/refreshes the Version Packages PR and **does not** publish. +That's why we publish locally — we keep the other changesets in `.changeset/` so the +Version Packages PR still tracks them, but we ship just the one we want now. + +Execute stages in order. Pause for user input where indicated. **Never execute the +`changeset publish` command yourself** — provide it to the user to run. + +## Stage 0: Confirm scope + +Identify the changeset to release and the target package + version. + +```bash +ls .changeset/ +git log --oneline -10 # find the PR/commit that added the changeset +cat .changeset/.md # confirm the package + bump type +npm view version dist-tags # confirm current published state +``` + +Confirm with the user: +- Which `.changeset/*.md` file is being released +- The target package and the resulting version (e.g., `1.0.2` → `1.0.3`) +- That **all other** changesets in `.changeset/` should remain queued for the next regular release + +If the package has notes in the [Package-specific notes](#package-specific-notes) section +below, review them before continuing. + +## Stage 1: Branch + quarantine + +Work on a release branch so the workflow doesn't trigger mid-flow. + +```bash +git switch canary && git pull +git switch -c release/- +``` + +Move the **other** changesets **outside** the repo. A subdirectory inside `.changeset/` +gets parsed as a malformed changeset by the CLI and crashes `changeset version`: + +```bash +mkdir -p /tmp/changeset-hold +mv .changeset/.md .changeset/.md ... /tmp/changeset-hold/ +ls .changeset/ # should leave only config.json + the one changeset to release +``` + +## Stage 2: Run `changeset version` + +Requires `GITHUB_TOKEN` because the repo uses `@changesets/changelog-github`. The `gh` +CLI token works. + +```bash +pnpm install --frozen-lockfile +GITHUB_TOKEN=$(gh auth token) pnpm changeset version +``` + +Restore the held changesets immediately: + +```bash +mv /tmp/changeset-hold/*.md .changeset/ +rmdir /tmp/changeset-hold +``` + +Verify the diff: + +```bash +git status +git diff packages//package.json packages//CHANGELOG.md +``` + +Expect: bumped `package.json`, new CHANGELOG entry, deleted only the one changeset. +The other changesets should be back in `.changeset/` and untouched. + +## Stage 3: Build + +Run the root build. Turborepo handles env passthrough from `.env.local` via the +pipeline config, so package builds get the variables they need without manual sourcing. + +```bash +pnpm build +``` + +If a package has build-time secrets that must be present, see the +[Package-specific notes](#package-specific-notes) section for verification steps. + +## Stage 4: Commit + +```bash +git add -A +git commit -m "Version Packages (\`canary\`)" +``` + +Match the message format the changesets bot uses, since this is a manual stand-in for it. + +## Stage 5: Hand the publish command to the user + +**Do not run `changeset publish` from the agent.** Publishing to npm is a destructive, +externally-visible action that should be performed by the user. + +Have the user confirm they're logged in, then run the publish themselves. The CLI will +prompt them interactively for the npm OTP. + +```bash +npm whoami # expect their npm username +pnpm exec changeset publish # prompts for OTP interactively +``` + +`changeset publish` is per-package version-aware: it only publishes packages whose local +`package.json` is ahead of npm. Since only one package was bumped, only it ships. It +also creates a local git tag like `@bigcommerce/@`. + +Wait for the user to confirm the publish completed before continuing. + +## Stage 6: Verify npm state + +```bash +npm view version +npm view dist-tags +``` + +`latest` should point to the new version. If it doesn't (rare — only happens if +`publishConfig.tag` is set), advise the user to fix with: + +```bash +npm dist-tag add @ latest +``` + +## Stage 7: Fast-forward canary and push + +This requires a direct push to the protected default branch. **Pause and ask for explicit +user authorization** before pushing — the user's "never push directly to main/master/production" +rule guards against this even though the changesets bot does the same thing during normal +releases. + +```bash +git switch canary +git fetch origin canary +git log --oneline origin/canary..canary # should be 1 ahead +git log --oneline canary..origin/canary # should be 0 behind +git merge --ff-only release/- +``` + +If you're 1 ahead and 0 behind, default `git push` rejects non-fast-forward updates, +which gives the same safety as `--ff-only` on the push side. Apple's git build (≤2.50.x) +does not accept `--ff-only` as a push flag — `git push origin canary` is correct here. + +If a hook blocks the agent push, hand these commands to the user: + +```bash +git push origin canary +git push origin "@bigcommerce/@" +``` + +## Stage 8: Create the GitHub release manually + +CI runs `changeset publish` after the canary push, finds the version already on npm, +and no-ops. Because the action only creates GitHub releases for packages it actually +publishes, **no release is created automatically** in this flow. Make it manually. + +Extract the new CHANGELOG section (everything after the `## ` heading up to +the next `## ` heading) into a notes file. Then: + +```bash +gh release create "@bigcommerce/@" \ + --repo bigcommerce/catalyst \ + --title "@bigcommerce/@" \ + --notes-file /tmp/release-notes.md +``` + +Match the body format of prior releases — just the `### Patch Changes` / +`### Minor Changes` heading and the bullets, no version heading at the top. Compare +against an existing release: + +```bash +gh release view "@bigcommerce/catalyst-core@" --repo bigcommerce/catalyst --json body +``` + +## Stage 9: Final validation + +```bash +git fetch origin canary +git log --oneline origin/canary -3 # version commit on canary +git ls-remote --tags origin "@bigcommerce/@" # tag on origin +gh release view "@bigcommerce/@" --repo bigcommerce/catalyst --json tagName,isDraft,isPrerelease +gh run list --workflow=changesets-release.yml --limit 1 # CI run succeeded +gh pr list --search "Version Packages (canary)" --state open --json number,headRefName,updatedAt # Version Packages PR refreshed +git fetch origin changeset-release/canary +git show --stat origin/changeset-release/canary | head -20 # confirm only the other changesets remain +npm view version dist-tags +``` + +Report: +- Published version + dist-tag +- Canary commit SHA +- Tag pushed +- GitHub release URL +- Confirmation that the Version Packages PR now contains **only** the other changesets — the released one has been dropped from its scope. + +## Stage 10: Cleanup + +```bash +git branch -d release/- +``` + +## Package-specific notes + +### `@bigcommerce/create-catalyst` + +The CLI build (`tsup` via the package's `tsup.config.ts`) inlines `CLI_SEGMENT_WRITE_KEY` +at build time, falling back to the placeholder `'not-a-valid-segment-write-key'` if the +env var is missing. After Stage 3, verify the real key was embedded: + +```bash +grep -c "not-a-valid-segment-write-key" packages/create-catalyst/dist/index.js +# expect: 0 +``` + +If `1`, the env var wasn't loaded. Confirm `CLI_SEGMENT_WRITE_KEY` exists in `.env.local`, +and that the turbo pipeline for `build` declares it under `env` or `passThroughEnv` in +`turbo.json`. Re-run `pnpm build` after fixing. From 24cc310e16f85f6f5d36d8b3c69c4b6ff02c600d Mon Sep 17 00:00:00 2001 From: Alex Saiannyi <67792608+bc-alexsaiannyi@users.noreply.github.com> Date: Wed, 6 May 2026 23:54:16 +0200 Subject: [PATCH 32/47] fix(core): TRAC-294 show manual checkout discounts in cart summary (#3002) --- .changeset/cold-foxes-lie.md | 5 +++++ core/app/[locale]/(default)/cart/page-data.ts | 8 ++++++++ core/app/[locale]/(default)/cart/page.tsx | 11 +++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .changeset/cold-foxes-lie.md diff --git a/.changeset/cold-foxes-lie.md b/.changeset/cold-foxes-lie.md new file mode 100644 index 0000000000..5a2cef8780 --- /dev/null +++ b/.changeset/cold-foxes-lie.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Fix cart summary Discounts row not showing manual discounts applied via the Management Checkout API diff --git a/core/app/[locale]/(default)/cart/page-data.ts b/core/app/[locale]/(default)/cart/page-data.ts index c6e47636dc..1d88b721e9 100644 --- a/core/app/[locale]/(default)/cart/page-data.ts +++ b/core/app/[locale]/(default)/cart/page-data.ts @@ -28,6 +28,10 @@ export const PhysicalItemFragment = graphql(` currencyCode value } + discountedAmount { + currencyCode + value + } selectedOptions { __typename entityId @@ -87,6 +91,10 @@ export const DigitalItemFragment = graphql(` currencyCode value } + discountedAmount { + currencyCode + value + } selectedOptions { __typename entityId diff --git a/core/app/[locale]/(default)/cart/page.tsx b/core/app/[locale]/(default)/cart/page.tsx index bc07f3d473..29f91be420 100644 --- a/core/app/[locale]/(default)/cart/page.tsx +++ b/core/app/[locale]/(default)/cart/page.tsx @@ -213,6 +213,13 @@ export default async function Cart({ params }: Props) { const totalCouponDiscount = checkout?.coupons.reduce((sum, coupon) => sum + coupon.discountedAmount.value, 0) ?? 0; + const totalLineItemDiscount = [ + ...cart.lineItems.physicalItems, + ...cart.lineItems.digitalItems, + ].reduce((sum, item) => sum + item.discountedAmount.value, 0); + + const totalDiscount = cart.discountedAmount.value + totalLineItemDiscount; + const giftCertificatesSummary = checkout?.giftCertificates.reduce>((acc, c) => { acc.push({ @@ -278,10 +285,10 @@ export default async function Cart({ params }: Props) { currency: cart.currencyCode, }), }, - cart.discountedAmount.value > 0 + totalDiscount > 0 ? { label: t('CheckoutSummary.discounts'), - value: `-${format.number(cart.discountedAmount.value, { + value: `-${format.number(totalDiscount, { style: 'currency', currency: cart.currencyCode, })}`, From 37e0a7cc99163fea5c22769483175f2509f556e7 Mon Sep 17 00:00:00 2001 From: mfaris9 Date: Fri, 8 May 2026 11:28:53 -0400 Subject: [PATCH 33/47] fix(core): TRAC-275 align formField.required with field.required for checkbox-group (#3005) * fix(core): align formField.required with field.required for checkbox-group * chore: fix prettier formatting * refactor: use if/else for checkbox-group schema per review --- .changeset/fix-checkbox-group-required.md | 6 ++++++ core/vibes/soul/form/dynamic-form/schema.ts | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-checkbox-group-required.md diff --git a/.changeset/fix-checkbox-group-required.md b/.changeset/fix-checkbox-group-required.md new file mode 100644 index 0000000000..02d0e3948e --- /dev/null +++ b/.changeset/fix-checkbox-group-required.md @@ -0,0 +1,6 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Fix `formField.required` mismatch for `checkbox-group` fields in `DynamicForm`. The schema branch was missing `.optional()` for non-required checkbox groups. + diff --git a/core/vibes/soul/form/dynamic-form/schema.ts b/core/vibes/soul/form/dynamic-form/schema.ts index f14f19a76b..4a0048d33f 100644 --- a/core/vibes/soul/form/dynamic-form/schema.ts +++ b/core/vibes/soul/form/dynamic-form/schema.ts @@ -302,7 +302,11 @@ function getFieldSchema( case 'checkbox-group': fieldSchema = z.string().array(); - if (field.required === true) fieldSchema = fieldSchema.nonempty(); + if (field.required === true) { + fieldSchema = fieldSchema.nonempty(); + } else { + fieldSchema = fieldSchema.optional(); + } break; From 77c8e8df9ce4c1fa5e1a3a5ac2fedcca8fb4ab20 Mon Sep 17 00:00:00 2001 From: bc-svc-local <102379007+bc-svc-local@users.noreply.github.com> Date: Mon, 11 May 2026 23:44:30 +0200 Subject: [PATCH 34/47] Update translations (#3008) * feat(other): LOCAL-1444 delivery translation * chore(core): create translations patch --------- Co-authored-by: bc-svc-local --- .changeset/translations-patch-580c6ed4.md | 5 +++++ core/messages/da.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/translations-patch-580c6ed4.md diff --git a/.changeset/translations-patch-580c6ed4.md b/.changeset/translations-patch-580c6ed4.md new file mode 100644 index 0000000000..ad17b2636a --- /dev/null +++ b/.changeset/translations-patch-580c6ed4.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Update translations. diff --git a/core/messages/da.json b/core/messages/da.json index 1bb6967bfc..e3325fad1e 100644 --- a/core/messages/da.json +++ b/core/messages/da.json @@ -586,7 +586,7 @@ }, "Footer": { "home": "Hjem", - "contactUs": "kontakte os", + "contactUs": "Kontakt os", "socialMediaLinks": "Links til sociale medier", "categories": "Kategorier", "brands": "mærker", From b47ace783fbbfe2ca11c9915010998ff33b62950 Mon Sep 17 00:00:00 2001 From: Yevhenii Buliuk <82589781+bc-yevhenii-buliuk@users.noreply.github.com> Date: Tue, 12 May 2026 09:49:52 +0300 Subject: [PATCH 35/47] fix(core): TRAC-277 translate Show more/less labels on product compare page (#3009) --- core/app/[locale]/(default)/compare/page.tsx | 2 ++ core/messages/en.json | 2 ++ core/vibes/soul/primitives/compare-card/index.tsx | 8 ++++++-- core/vibes/soul/sections/compare-section/index.tsx | 6 ++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/core/app/[locale]/(default)/compare/page.tsx b/core/app/[locale]/(default)/compare/page.tsx index ac851ddb1a..6a063f7dec 100644 --- a/core/app/[locale]/(default)/compare/page.tsx +++ b/core/app/[locale]/(default)/compare/page.tsx @@ -126,6 +126,8 @@ export default async function Compare(props: Props) { previousLabel={t('previous')} products={streamableProducts} ratingLabel={t('rating')} + showLessLabel={t('showLess')} + showMoreLabel={t('showMore')} title={t('title')} viewOptionsLabel={t('viewOptions')} /> diff --git a/core/messages/en.json b/core/messages/en.json index 7fa3590394..56a54ac058 100644 --- a/core/messages/en.json +++ b/core/messages/en.json @@ -444,6 +444,8 @@ "otherDetails": "Other details", "noOtherDetails": "There are no other details.", "viewOptions": "View options", + "showMore": "Show more", + "showLess": "Show less", "successMessage": "{cartItems, plural, =1 {1 item} other {# items}} added to your cart", "missingCart": "Cart not found. Please try again later.", "unknownError": "Unknown error. Please try again later." diff --git a/core/vibes/soul/primitives/compare-card/index.tsx b/core/vibes/soul/primitives/compare-card/index.tsx index 2a51f6ec0a..dacaaede34 100644 --- a/core/vibes/soul/primitives/compare-card/index.tsx +++ b/core/vibes/soul/primitives/compare-card/index.tsx @@ -33,6 +33,8 @@ export interface CompareCardProps { noOtherDetailsLabel?: string; viewOptionsLabel?: string; preorderLabel?: string; + showMoreLabel?: string; + showLessLabel?: string; addToCartAction?: CompareAddToCartAction; imageSizes?: string; } @@ -66,6 +68,8 @@ export function CompareCard({ noOtherDetailsLabel = 'There are no other details.', viewOptionsLabel = 'View options', preorderLabel = 'Preorder', + showMoreLabel = 'Show more', + showLessLabel = 'Show less', imageSizes, }: CompareCardProps) { return ( @@ -110,7 +114,7 @@ export function CompareCard({ {descriptionLabel} {product.description != null && product.description !== '' ? ( - +
{product.description}
) : ( @@ -124,7 +128,7 @@ export function CompareCard({
{otherDetailsLabel}
- +
{product.customFields.map((field, index) => ( diff --git a/core/vibes/soul/sections/compare-section/index.tsx b/core/vibes/soul/sections/compare-section/index.tsx index 5121bf81e1..7372d6141e 100644 --- a/core/vibes/soul/sections/compare-section/index.tsx +++ b/core/vibes/soul/sections/compare-section/index.tsx @@ -33,6 +33,8 @@ interface CompareSectionProps { noOtherDetailsLabel?: string; viewOptionsLabel?: string; preorderLabel?: string; + showMoreLabel?: string; + showLessLabel?: string; placeholderCount?: number; addToCartAction?: CompareAddToCartAction; } @@ -72,6 +74,8 @@ export function CompareSection({ noOtherDetailsLabel, viewOptionsLabel, preorderLabel, + showMoreLabel, + showLessLabel, placeholderCount, }: CompareSectionProps) { return ( @@ -129,6 +133,8 @@ export function CompareSection({ preorderLabel={preorderLabel} product={product} ratingLabel={ratingLabel} + showLessLabel={showLessLabel} + showMoreLabel={showMoreLabel} viewOptionsLabel={viewOptionsLabel} /> From 13b3c2e5c85bf47a07e999315a8f12988ab96d3f Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Wed, 13 May 2026 10:46:41 -0600 Subject: [PATCH 36/47] fix(core): TRAC-668 bump Next.js, React, and opennextjs/cloudflare for security patches (#3007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses multiple CVEs disclosed May 2026: - next: ~16.1.6 → ~16.2.6 (middleware bypass, SSRF, XSS, cache poisoning) - react/react-dom: 19.1.5 → 19.1.7 (GHSA-rv78-f8rc-xrxh DoS via OOM/CPU on server function endpoints) - @opennextjs/cloudflare: 1.17.3 → 1.19.9 in native-hosting workflow eslint-config-next intentionally left at 15.5.10 — @16.x requires ESLint 9+/flat config migration. Fixes TRAC-668 Co-authored-by: Claude --- .changeset/security-bump-nextjs-react.md | 8 + .github/workflows/native-hosting.yml | 2 +- core/package.json | 6 +- pnpm-lock.yaml | 1053 ++++++++++++---------- 4 files changed, 566 insertions(+), 503 deletions(-) create mode 100644 .changeset/security-bump-nextjs-react.md diff --git a/.changeset/security-bump-nextjs-react.md b/.changeset/security-bump-nextjs-react.md new file mode 100644 index 0000000000..63c8b92c3f --- /dev/null +++ b/.changeset/security-bump-nextjs-react.md @@ -0,0 +1,8 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Bump Next.js and React to address security vulnerabilities + +- `next`: ~16.1.6 → ~16.2.6 — fixes middleware bypass, SSRF, XSS, and cache poisoning CVEs +- `react` / `react-dom`: 19.1.5 → 19.1.7 — fixes GHSA-rv78-f8rc-xrxh (DoS via OOM/CPU exhaustion on server function endpoints) diff --git a/.github/workflows/native-hosting.yml b/.github/workflows/native-hosting.yml index 456db9b4d4..134e7fc902 100644 --- a/.github/workflows/native-hosting.yml +++ b/.github/workflows/native-hosting.yml @@ -26,7 +26,7 @@ jobs: run: pnpm install --frozen-lockfile - name: Install Catalyst CLI - run: pnpm add @bigcommerce/catalyst@alpha @opennextjs/cloudflare@1.17.3 + run: pnpm add @bigcommerce/catalyst@alpha @opennextjs/cloudflare@latest working-directory: core - name: Convert proxy.ts to middleware.ts diff --git a/core/package.json b/core/package.json index d9b6cd3a34..d14297e340 100644 --- a/core/package.json +++ b/core/package.json @@ -60,14 +60,14 @@ "lodash.debounce": "^4.0.8", "lru-cache": "^11.1.0", "lucide-react": "^0.474.0", - "next": "~16.1.6", + "next": "~16.2.6", "next-auth": "5.0.0-beta.30", "next-intl": "^4.6.1", "nuqs": "^2.4.3", "p-lazy": "^5.0.0", - "react": "19.1.5", + "react": "19.1.7", "react-day-picker": "^9.7.0", - "react-dom": "19.1.5", + "react-dom": "19.1.7", "react-google-recaptcha": "^3.1.0", "react-headroom": "^3.2.1", "schema-dts": "^1.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18248ad97d..4dcb7d3b37 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,16 +43,16 @@ importers: version: link:../packages/client '@c15t/nextjs': specifier: ^1.8.2 - version: 1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2) + version: 1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react-dom@19.1.7(react@19.1.7))(react@19.1.7)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2) '@conform-to/react': specifier: ^1.6.1 - version: 1.6.1(react@19.1.5) + version: 1.6.1(react@19.1.7) '@conform-to/zod': specifier: ^1.6.1 version: 1.6.1(zod@3.25.51) '@icons-pack/react-simple-icons': specifier: ^11.2.0 - version: 11.2.0(react@19.1.5) + version: 11.2.0(react@19.1.7) '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -67,46 +67,46 @@ importers: version: 0.208.0(@opentelemetry/api@1.9.0) '@radix-ui/react-accordion': specifier: ^1.2.11 - version: 1.2.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.2.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-checkbox': specifier: ^1.3.2 - version: 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-dialog': specifier: ^1.1.14 - version: 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-dropdown-menu': specifier: ^2.1.15 - version: 2.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 2.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-label': specifier: ^2.1.7 - version: 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-navigation-menu': specifier: ^1.2.13 - version: 1.2.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.2.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-popover': specifier: ^1.1.14 - version: 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-portal': specifier: ^1.1.9 - version: 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-radio-group': specifier: ^1.3.7 - version: 1.3.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.3.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-select': specifier: ^2.2.5 - version: 2.2.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 2.2.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-switch': specifier: ^1.2.5 - version: 1.2.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.2.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-toggle': specifier: ^1.1.9 - version: 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-toggle-group': specifier: ^1.1.10 - version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@radix-ui/react-tooltip': specifier: ^1.2.7 - version: 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) '@t3-oss/env-core': specifier: ^0.13.6 version: 0.13.6(typescript@5.8.3)(zod@3.25.51) @@ -115,7 +115,7 @@ importers: version: 1.35.0 '@vercel/analytics': specifier: ^1.5.0 - version: 1.5.0(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3)) + version: 1.5.0(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3)) '@vercel/functions': specifier: ^2.2.12 version: 2.2.12(@aws-sdk/credential-provider-web-identity@3.864.0) @@ -124,7 +124,7 @@ importers: version: 2.1.0(@opentelemetry/api-logs@0.208.0)(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-logs@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@2.0.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)) '@vercel/speed-insights': specifier: ^1.2.0 - version: 1.2.0(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3)) + version: 1.2.0(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3)) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -148,7 +148,7 @@ importers: version: 9.0.0-rc01(embla-carousel@9.0.0-rc01) embla-carousel-react: specifier: 9.0.0-rc01 - version: 9.0.0-rc01(react@19.1.5) + version: 9.0.0-rc01(react@19.1.7) gql.tada: specifier: ^1.8.10 version: 1.8.10(graphql@16.11.0)(typescript@5.8.3) @@ -166,37 +166,37 @@ importers: version: 11.1.0 lucide-react: specifier: ^0.474.0 - version: 0.474.0(react@19.1.5) + version: 0.474.0(react@19.1.7) next: - specifier: ~16.1.6 - version: 16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + specifier: ~16.2.6 + version: 16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) next-auth: specifier: 5.0.0-beta.30 - version: 5.0.0-beta.30(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5) + version: 5.0.0-beta.30(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7) next-intl: specifier: ^4.6.1 - version: 4.8.3(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5)(typescript@5.8.3) + version: 4.8.3(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7)(typescript@5.8.3) nuqs: specifier: ^2.4.3 - version: 2.4.3(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5) + version: 2.4.3(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7) p-lazy: specifier: ^5.0.0 version: 5.0.0 react: - specifier: 19.1.5 - version: 19.1.5 + specifier: 19.1.7 + version: 19.1.7 react-day-picker: specifier: ^9.7.0 - version: 9.7.0(react@19.1.5) + version: 9.7.0(react@19.1.7) react-dom: - specifier: 19.1.5 - version: 19.1.5(react@19.1.5) + specifier: 19.1.7 + version: 19.1.7(react@19.1.7) react-google-recaptcha: specifier: ^3.1.0 - version: 3.1.0(react@19.1.5) + version: 3.1.0(react@19.1.7) react-headroom: specifier: ^3.2.1 - version: 3.2.1(react@19.1.5) + version: 3.2.1(react@19.1.7) schema-dts: specifier: ^1.1.5 version: 1.1.5 @@ -205,7 +205,7 @@ importers: version: 0.0.1 sonner: specifier: ^1.7.4 - version: 1.7.4(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + version: 1.7.4(react-dom@19.1.7(react@19.1.7))(react@19.1.7) tailwindcss-radix: specifier: ^3.0.5 version: 3.0.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3))) @@ -2509,8 +2509,8 @@ packages: '@next/bundle-analyzer@16.1.6': resolution: {integrity: sha512-ee2kagdTaeEWPlotgdTOqFHYcD3e2m2bbE3I9Rq2i6ABYi5OgopmtEUe8NM23viaYxLV2tDH/2nd5+qKoEr6cw==} - '@next/env@16.1.6': - resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + '@next/env@16.2.6': + resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==} '@next/eslint-plugin-next@15.3.3': resolution: {integrity: sha512-VKZJEiEdpKkfBmcokGjHu0vGDG+8CehGs90tBEy/IDoDDKGngeyIStt2MmE5FYNyU9BhgR7tybNWTAJY/30u+Q==} @@ -2518,50 +2518,50 @@ packages: '@next/eslint-plugin-next@15.5.10': resolution: {integrity: sha512-fDpxcy6G7Il4lQVVsaJD0fdC2/+SmuBGTF+edRLlsR4ZFOE3W2VyzrrGYdg/pHW8TydeAdSVM+mIzITGtZ3yWA==} - '@next/swc-darwin-arm64@16.1.6': - resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} + '@next/swc-darwin-arm64@16.2.6': + resolution: {integrity: sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.1.6': - resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} + '@next/swc-darwin-x64@16.2.6': + resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.1.6': - resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} + '@next/swc-linux-arm64-gnu@16.2.6': + resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@16.1.6': - resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} + '@next/swc-linux-arm64-musl@16.2.6': + resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@16.1.6': - resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} + '@next/swc-linux-x64-gnu@16.2.6': + resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@16.1.6': - resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} + '@next/swc-linux-x64-musl@16.2.6': + resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@16.1.6': - resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} + '@next/swc-win32-arm64-msvc@16.2.6': + resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.1.6': - resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} + '@next/swc-win32-x64-msvc@16.2.6': + resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -8057,8 +8057,8 @@ packages: typescript: optional: true - next@16.1.6: - resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + next@16.2.6: + resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -8901,10 +8901,10 @@ packages: peerDependencies: react: '>=16.8.0' - react-dom@19.1.5: - resolution: {integrity: sha512-tvMijysf97vcHla1PNI/aU2apv7f4r0ct0OBk3i3QOBfsVhZzHEuPBLemClkfuw8LroE4FH6kXcQOftf2ntPHQ==} + react-dom@19.1.7: + resolution: {integrity: sha512-hE2iTlqZDmmCBRpmXbzHJLngNeHfLtdMA1qp4eDreMgdtbCgFAWGJhvD2u1KF0UQe5W5y2cQkpjAYTGhXbil4A==} peerDependencies: - react: ^19.1.5 + react: ^19.1.7 react-google-recaptcha@3.1.0: resolution: {integrity: sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==} @@ -8952,8 +8952,8 @@ packages: '@types/react': optional: true - react@19.1.5: - resolution: {integrity: sha512-lCX00zqONdNfcnJYEL91LuNYzyWFU70vKhApUR08Y1Fi/Y5FGw6l6hAWtlkq+k/vnx463XLm/5dyQp5HAJCw6Q==} + react@19.1.7: + resolution: {integrity: sha512-sExZFfembjCLTr9ran4JS8W2Z9m3d0lbrOAuFreAR8krpw76YnK+lnzlkO4OvFjEuHzKc8rw94h0EAVSh/Gn+w==} engines: {node: '>=0.10.0'} read-cache@1.0.0: @@ -11667,9 +11667,9 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-config-prettier: 9.1.0(eslint@8.57.1) - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-gettext: 1.2.0 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jest: 28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) eslint-plugin-jest-dom: 5.5.0(eslint@8.57.1) eslint-plugin-jest-formatting: 3.1.0(eslint@8.57.1) @@ -11774,13 +11774,13 @@ snapshots: neverthrow: 8.2.0 picocolors: 1.1.1 - '@c15t/nextjs@1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react-dom@19.1.5(react@19.1.5))(react@19.1.5)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2)': + '@c15t/nextjs@1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react-dom@19.1.7(react@19.1.7))(react@19.1.7)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2)': dependencies: - '@c15t/react': 1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2) + '@c15t/react': 1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2) '@c15t/translations': 1.8.0 - next: 16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + next: 16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) transitivePeerDependencies: - '@aws-sdk/client-rds-data' - '@cloudflare/workers-types' @@ -11822,16 +11822,16 @@ snapshots: - use-sync-external-store - ws - '@c15t/react@1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2)': + '@c15t/react@1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2)': dependencies: - '@radix-ui/react-accordion': 1.2.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-slot': 1.2.0(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-switch': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - c15t: 1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(react@19.1.5)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2) + '@radix-ui/react-accordion': 1.2.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-slot': 1.2.0(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-switch': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + c15t: 1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(react@19.1.7)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2) clsx: 2.1.1 - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) - zustand: 5.0.8(@types/react@19.2.7)(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) + zustand: 5.0.8(@types/react@19.2.7)(react@19.1.7) transitivePeerDependencies: - '@aws-sdk/client-rds-data' - '@cloudflare/workers-types' @@ -12074,10 +12074,10 @@ snapshots: '@conform-to/dom@1.6.1': {} - '@conform-to/react@1.6.1(react@19.1.5)': + '@conform-to/react@1.6.1(react@19.1.7)': dependencies: '@conform-to/dom': 1.6.1 - react: 19.1.5 + react: 19.1.7 '@conform-to/zod@1.6.1(zod@3.25.51)': dependencies: @@ -12583,11 +12583,11 @@ snapshots: '@floating-ui/core': 1.7.1 '@floating-ui/utils': 0.2.9 - '@floating-ui/react-dom@2.1.3(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@floating-ui/react-dom@2.1.3(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@floating-ui/dom': 1.7.1 - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) '@floating-ui/utils@0.2.9': {} @@ -12688,9 +12688,9 @@ snapshots: '@iarna/toml@2.2.5': {} - '@icons-pack/react-simple-icons@11.2.0(react@19.1.5)': + '@icons-pack/react-simple-icons@11.2.0(react@19.1.7)': dependencies: - react: 19.1.5 + react: 19.1.7 '@img/colour@1.1.0': optional: true @@ -13304,7 +13304,7 @@ snapshots: - bufferutil - utf-8-validate - '@next/env@16.1.6': {} + '@next/env@16.2.6': {} '@next/eslint-plugin-next@15.3.3': dependencies: @@ -13314,28 +13314,28 @@ snapshots: dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@16.1.6': + '@next/swc-darwin-arm64@16.2.6': optional: true - '@next/swc-darwin-x64@16.1.6': + '@next/swc-darwin-x64@16.2.6': optional: true - '@next/swc-linux-arm64-gnu@16.1.6': + '@next/swc-linux-arm64-gnu@16.2.6': optional: true - '@next/swc-linux-arm64-musl@16.1.6': + '@next/swc-linux-arm64-musl@16.2.6': optional: true - '@next/swc-linux-x64-gnu@16.1.6': + '@next/swc-linux-x64-gnu@16.2.6': optional: true - '@next/swc-linux-x64-musl@16.1.6': + '@next/swc-linux-x64-musl@16.2.6': optional: true - '@next/swc-win32-arm64-msvc@16.1.6': + '@next/swc-win32-arm64-msvc@16.2.6': optional: true - '@next/swc-win32-x64-msvc@16.1.6': + '@next/swc-win32-x64-msvc@16.2.6': optional: true '@noble/ciphers@1.3.0': {} @@ -13994,579 +13994,579 @@ snapshots: '@radix-ui/primitive@1.1.2': {} - '@radix-ui/react-accordion@1.2.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-accordion@1.2.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collapsible': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-collapsible': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-accordion@1.2.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-accordion@1.2.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collapsible': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-collection': 1.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-collapsible': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-collection': 1.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-collapsible@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-collapsible@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-collapsible@1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-collapsible@1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-presence': 1.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-presence': 1.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-collection@1.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-collection@1.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-slot': 1.2.0(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-slot': 1.2.0(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.7)(react@19.1.7)': dependencies: - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-context@1.1.2(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.7)(react@19.1.7)': dependencies: - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-dialog@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-dialog@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) aria-hidden: 1.2.6 - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) - react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) + react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-direction@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-dropdown-menu@2.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-dropdown-menu@2.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-focus-guards@1.1.2(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-focus-guards@1.1.2(@types/react@19.2.7)(react@19.1.7)': dependencies: - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-id@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-menu@2.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-menu@2.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) aria-hidden: 1.2.6 - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) - react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) + react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-navigation-menu@1.2.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-navigation-menu@1.2.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-popover@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-popover@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) aria-hidden: 1.2.6 - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) - react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) + react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-popper@1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': - dependencies: - '@floating-ui/react-dom': 2.1.3(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.5) + '@radix-ui/react-popper@1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': + dependencies: + '@floating-ui/react-dom': 2.1.3(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.7) '@radix-ui/rect': 1.1.1 - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-presence@1.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-presence@1.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-presence@1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-presence@1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-primitive@2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-primitive@2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-slot': 1.2.0(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-slot': 1.2.0(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-radio-group@1.3.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-radio-group@1.3.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-select@2.2.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-select@2.2.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) aria-hidden: 1.2.6 - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) - react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) + react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-slot@1.2.0(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-slot@1.2.0(@types/react@19.2.7)(react@19.1.7)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-slot@1.2.3(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.7)(react@19.1.7)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-switch@1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-switch@1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-switch@1.2.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-switch@1.2.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-toggle-group@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-toggle-group@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-toggle': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-toggle': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-toggle@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-toggle@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-tooltip@1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-tooltip@1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-use-controllable-state@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-controllable-state@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.7)(react@19.1.7)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.7)(react@19.1.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.7)(react@19.1.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.7)(react@19.1.7)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: '@radix-ui/rect': 1.1.1 - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.7)(react@19.1.5)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.7)(react@19.1.7)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.5) - react: 19.1.5 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.1.7) + react: 19.1.7 optionalDependencies: '@types/react': 19.2.7 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) @@ -16211,10 +16211,10 @@ snapshots: dependencies: uncrypto: 0.1.3 - '@vercel/analytics@1.5.0(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3))': + '@vercel/analytics@1.5.0(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3))': optionalDependencies: - next: 16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 + next: 16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 svelte: 5.1.15 vue: 3.5.16(typescript@5.8.3) @@ -16239,10 +16239,10 @@ snapshots: '@opentelemetry/sdk-metrics': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@vercel/speed-insights@1.2.0(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3))': + '@vercel/speed-insights@1.2.0(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3))': optionalDependencies: - next: 16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 + next: 16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 svelte: 5.1.15 vue: 3.5.16(typescript@5.8.3) @@ -16794,13 +16794,13 @@ snapshots: optionalDependencies: magicast: 0.3.5 - c15t@1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(react@19.1.5)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2): + c15t@1.8.2(@opentelemetry/api@1.9.0)(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@types/react@19.2.7)(@upstash/redis@1.35.0)(crossws@0.3.5)(react@19.1.7)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2): dependencies: '@c15t/backend': 1.8.0(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@upstash/redis@1.35.0)(crossws@0.3.5)(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2) '@c15t/translations': 1.8.0 '@orpc/client': 1.8.1(@opentelemetry/api@1.9.0) '@orpc/server': 1.8.1(@opentelemetry/api@1.9.0)(crossws@0.3.5)(ws@8.18.2) - zustand: 5.0.8(@types/react@19.2.7)(react@19.1.5) + zustand: 5.0.8(@types/react@19.2.7)(react@19.1.7) transitivePeerDependencies: - '@aws-sdk/client-rds-data' - '@cloudflare/workers-types' @@ -17470,11 +17470,11 @@ snapshots: dependencies: embla-carousel: 9.0.0-rc01 - embla-carousel-react@9.0.0-rc01(react@19.1.5): + embla-carousel-react@9.0.0-rc01(react@19.1.7): dependencies: embla-carousel: 9.0.0-rc01 embla-carousel-reactive-utils: 9.0.0-rc01(embla-carousel@9.0.0-rc01) - react: 19.1.5 + react: 19.1.7 embla-carousel-reactive-utils@9.0.0-rc01(embla-carousel@9.0.0-rc01): dependencies: @@ -17709,8 +17709,8 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -17737,6 +17737,21 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.1 + eslint: 8.57.1 + get-tsconfig: 4.10.0 + is-bun-module: 1.3.0 + rspack-resolver: 1.2.2 + stable-hash: 0.0.5 + tinyglobby: 0.2.14 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 @@ -17753,6 +17768,17 @@ snapshots: - supports-color eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -17773,7 +17799,7 @@ snapshots: dependencies: gettext-parser: 4.2.0 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -17802,6 +17828,35 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + eslint-plugin-jest-dom@5.5.0(eslint@8.57.1): dependencies: '@babel/runtime': 7.26.7 @@ -19312,7 +19367,7 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.7.2 + semver: 7.7.4 transitivePeerDependencies: - supports-color @@ -19752,9 +19807,9 @@ snapshots: lru_map@0.3.3: {} - lucide-react@0.474.0(react@19.1.5): + lucide-react@0.474.0(react@19.1.7): dependencies: - react: 19.1.5 + react: 19.1.7 magic-string@0.30.17: dependencies: @@ -19777,7 +19832,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.4 make-error@1.3.6: optional: true @@ -19956,50 +20011,50 @@ snapshots: optionalDependencies: '@rollup/rollup-linux-x64-gnu': 4.44.2 - next-auth@5.0.0-beta.30(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5): + next-auth@5.0.0-beta.30(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7): dependencies: '@auth/core': 0.41.0 - next: 16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) - react: 19.1.5 + next: 16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) + react: 19.1.7 next-intl-swc-plugin-extractor@4.8.3: {} - next-intl@4.8.3(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5)(typescript@5.8.3): + next-intl@4.8.3(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7)(typescript@5.8.3): dependencies: '@formatjs/intl-localematcher': 0.8.1 '@parcel/watcher': 2.5.1 '@swc/core': 1.15.18 icu-minify: 4.8.3 negotiator: 1.0.0 - next: 16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + next: 16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) next-intl-swc-plugin-extractor: 4.8.3 po-parser: 2.1.1 - react: 19.1.5 - use-intl: 4.8.3(react@19.1.5) + react: 19.1.7 + use-intl: 4.8.3(react@19.1.7) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: - '@swc/helpers' - next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5): + next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7): dependencies: - '@next/env': 16.1.6 + '@next/env': 16.2.6 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.7 caniuse-lite: 1.0.30001721 postcss: 8.4.31 - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) - styled-jsx: 5.1.6(@babel/core@7.27.4)(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) + styled-jsx: 5.1.6(@babel/core@7.27.4)(react@19.1.7) optionalDependencies: - '@next/swc-darwin-arm64': 16.1.6 - '@next/swc-darwin-x64': 16.1.6 - '@next/swc-linux-arm64-gnu': 16.1.6 - '@next/swc-linux-arm64-musl': 16.1.6 - '@next/swc-linux-x64-gnu': 16.1.6 - '@next/swc-linux-x64-musl': 16.1.6 - '@next/swc-win32-arm64-msvc': 16.1.6 - '@next/swc-win32-x64-msvc': 16.1.6 + '@next/swc-darwin-arm64': 16.2.6 + '@next/swc-darwin-x64': 16.2.6 + '@next/swc-linux-arm64-gnu': 16.2.6 + '@next/swc-linux-arm64-musl': 16.2.6 + '@next/swc-linux-x64-gnu': 16.2.6 + '@next/swc-linux-x64-musl': 16.2.6 + '@next/swc-win32-arm64-msvc': 16.2.6 + '@next/swc-win32-x64-msvc': 16.2.6 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.52.0 sharp: 0.34.5 @@ -20050,12 +20105,12 @@ snapshots: dependencies: boolbase: 1.0.0 - nuqs@2.4.3(next@16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5))(react@19.1.5): + nuqs@2.4.3(next@16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7))(react@19.1.7): dependencies: mitt: 3.0.1 - react: 19.1.5 + react: 19.1.7 optionalDependencies: - next: 16.1.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.5(react@19.1.5))(react@19.1.5) + next: 16.2.6(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.7(react@19.1.7))(react@19.1.7) nwsapi@2.2.20: optional: true @@ -20827,69 +20882,69 @@ snapshots: defu: 6.1.4 destr: 2.0.5 - react-async-script@1.2.0(react@19.1.5): + react-async-script@1.2.0(react@19.1.7): dependencies: hoist-non-react-statics: 3.3.2 prop-types: 15.8.1 - react: 19.1.5 + react: 19.1.7 - react-day-picker@9.7.0(react@19.1.5): + react-day-picker@9.7.0(react@19.1.7): dependencies: '@date-fns/tz': 1.2.0 date-fns: 4.1.0 date-fns-jalali: 4.1.0-0 - react: 19.1.5 + react: 19.1.7 - react-dom@19.1.5(react@19.1.5): + react-dom@19.1.7(react@19.1.7): dependencies: - react: 19.1.5 + react: 19.1.7 scheduler: 0.26.0 - react-google-recaptcha@3.1.0(react@19.1.5): + react-google-recaptcha@3.1.0(react@19.1.7): dependencies: prop-types: 15.8.1 - react: 19.1.5 - react-async-script: 1.2.0(react@19.1.5) + react: 19.1.7 + react-async-script: 1.2.0(react@19.1.7) - react-headroom@3.2.1(react@19.1.5): + react-headroom@3.2.1(react@19.1.7): dependencies: prop-types: 15.8.1 raf: 3.4.1 - react: 19.1.5 + react: 19.1.7 shallowequal: 1.1.0 react-is@16.13.1: {} react-is@18.3.1: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.7)(react@19.1.5): + react-remove-scroll-bar@2.3.8(@types/react@19.2.7)(react@19.1.7): dependencies: - react: 19.1.5 - react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.1.5) + react: 19.1.7 + react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.1.7) tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.7 - react-remove-scroll@2.7.1(@types/react@19.2.7)(react@19.1.5): + react-remove-scroll@2.7.1(@types/react@19.2.7)(react@19.1.7): dependencies: - react: 19.1.5 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.7)(react@19.1.5) - react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.1.5) + react: 19.1.7 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.7)(react@19.1.7) + react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.1.7) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.7)(react@19.1.5) - use-sidecar: 1.1.3(@types/react@19.2.7)(react@19.1.5) + use-callback-ref: 1.3.3(@types/react@19.2.7)(react@19.1.7) + use-sidecar: 1.1.3(@types/react@19.2.7)(react@19.1.7) optionalDependencies: '@types/react': 19.2.7 - react-style-singleton@2.2.3(@types/react@19.2.7)(react@19.1.5): + react-style-singleton@2.2.3(@types/react@19.2.7)(react@19.1.7): dependencies: get-nonce: 1.0.1 - react: 19.1.5 + react: 19.1.7 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.7 - react@19.1.5: {} + react@19.1.7: {} read-cache@1.0.0: dependencies: @@ -21320,10 +21375,10 @@ snapshots: ip-address: 9.0.5 smart-buffer: 4.2.0 - sonner@1.7.4(react-dom@19.1.5(react@19.1.5))(react@19.1.5): + sonner@1.7.4(react-dom@19.1.7(react@19.1.7))(react@19.1.7): dependencies: - react: 19.1.5 - react-dom: 19.1.5(react@19.1.5) + react: 19.1.7 + react-dom: 19.1.7(react@19.1.7) source-map-js@1.2.1: {} @@ -21505,10 +21560,10 @@ snapshots: stubborn-fs@1.2.5: {} - styled-jsx@5.1.6(@babel/core@7.27.4)(react@19.1.5): + styled-jsx@5.1.6(@babel/core@7.27.4)(react@19.1.7): dependencies: client-only: 0.0.1 - react: 19.1.5 + react: 19.1.7 optionalDependencies: '@babel/core': 7.27.4 @@ -22137,25 +22192,25 @@ snapshots: urlpattern-polyfill@10.0.0: {} - use-callback-ref@1.3.3(@types/react@19.2.7)(react@19.1.5): + use-callback-ref@1.3.3(@types/react@19.2.7)(react@19.1.7): dependencies: - react: 19.1.5 + react: 19.1.7 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.7 - use-intl@4.8.3(react@19.1.5): + use-intl@4.8.3(react@19.1.7): dependencies: '@formatjs/fast-memoize': 3.1.0 '@schummar/icu-type-parser': 1.21.5 icu-minify: 4.8.3 intl-messageformat: 11.1.2 - react: 19.1.5 + react: 19.1.7 - use-sidecar@1.1.3(@types/react@19.2.7)(react@19.1.5): + use-sidecar@1.1.3(@types/react@19.2.7)(react@19.1.7): dependencies: detect-node-es: 1.1.0 - react: 19.1.5 + react: 19.1.7 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.7 @@ -22551,7 +22606,7 @@ snapshots: zod@4.1.12: {} - zustand@5.0.8(@types/react@19.2.7)(react@19.1.5): + zustand@5.0.8(@types/react@19.2.7)(react@19.1.7): optionalDependencies: '@types/react': 19.2.7 - react: 19.1.5 + react: 19.1.7 From bfafc5621f6a6b8936d535b14bd241a4d79e0b2b Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Wed, 13 May 2026 10:55:11 -0600 Subject: [PATCH 37/47] Version Packages (`canary`) --- .changeset/security-bump-nextjs-react.md | 8 -------- core/CHANGELOG.md | 8 ++++++++ core/package.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 .changeset/security-bump-nextjs-react.md diff --git a/.changeset/security-bump-nextjs-react.md b/.changeset/security-bump-nextjs-react.md deleted file mode 100644 index 63c8b92c3f..0000000000 --- a/.changeset/security-bump-nextjs-react.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@bigcommerce/catalyst-core": patch ---- - -Bump Next.js and React to address security vulnerabilities - -- `next`: ~16.1.6 → ~16.2.6 — fixes middleware bypass, SSRF, XSS, and cache poisoning CVEs -- `react` / `react-dom`: 19.1.5 → 19.1.7 — fixes GHSA-rv78-f8rc-xrxh (DoS via OOM/CPU exhaustion on server function endpoints) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index eb51225d48..f1e3c1ddaf 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.6.3 + +### Patch Changes + +- [#3007](https://github.com/bigcommerce/catalyst/pull/3007) [`13b3c2e`](https://github.com/bigcommerce/catalyst/commit/13b3c2e5c85bf47a07e999315a8f12988ab96d3f) Thanks [@chanceaclark](https://github.com/chanceaclark)! - Bump Next.js and React to address security vulnerabilities + - `next`: ~16.1.6 → ~16.2.6 — fixes middleware bypass, SSRF, XSS, and cache poisoning CVEs + - `react` / `react-dom`: 19.1.5 → 19.1.7 — fixes GHSA-rv78-f8rc-xrxh (DoS via OOM/CPU exhaustion on server function endpoints) + ## 1.6.2 ### Patch Changes diff --git a/core/package.json b/core/package.json index d14297e340..37d0af9230 100644 --- a/core/package.json +++ b/core/package.json @@ -1,7 +1,7 @@ { "name": "@bigcommerce/catalyst-core", "description": "BigCommerce Catalyst is a Next.js starter kit for building headless BigCommerce storefronts.", - "version": "1.6.2", + "version": "1.6.3", "private": true, "engines": { "node": ">=24.0.0" From 20204c89f3d43f0d92a91c35ea7b53902eaa56a4 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Wed, 13 May 2026 14:52:08 -0600 Subject: [PATCH 38/47] Version Packages (`integrations/makeswift`) --- core/CHANGELOG.md | 8 ++++++++ core/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index f74c66fbe4..7b8cadd662 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.6.4 + +### Patch Changes + +- 4a5c2d8: Bump Next.js and React to address security vulnerabilities + - `next`: ~16.1.6 → ~16.2.6 — fixes middleware bypass, SSRF, XSS, and cache poisoning CVEs + - `react` / `react-dom`: 19.1.5 → 19.1.7 — fixes GHSA-rv78-f8rc-xrxh (DoS via OOM/CPU exhaustion on server function endpoints) + ## 1.6.3 ### Patch Changes diff --git a/core/package.json b/core/package.json index fc55e8ef3a..4b49186144 100644 --- a/core/package.json +++ b/core/package.json @@ -1,7 +1,7 @@ { "name": "@bigcommerce/catalyst-makeswift", "description": "BigCommerce Catalyst is a Next.js starter kit for building headless BigCommerce storefronts.", - "version": "1.6.3", + "version": "1.6.4", "private": true, "engines": { "node": ">=24.0.0" From 9aacfdccfbd081092f98b320028bd5e0d6c6b2bb Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Thu, 14 May 2026 13:32:18 -0600 Subject: [PATCH 39/47] fix(core): TRAC-293 pass customer token through routes and webpages (#3013) Customer-only webpages were inaccessible and missing from navigation when logged in. The with-routes proxy and the normal/contact webpage page-data queries resolved routes anonymously, so the Storefront API hid customer-restricted content from authenticated users. - Wrap the with-routes proxy handler in auth() and thread the customer access token into getRoute and getRawWebPageContent - Bypass the KV route cache when a customer access token is present; the cache key isn't namespaced by customer identity, so reading or writing it for authenticated requests could leak customer-specific route resolutions across users - Pass the customer access token into normal and contact webpage page-data queries, switching to a no-store fetch when authenticated so cached anonymous responses are not served to logged-in customers - Leave getStoreStatus unchanged (does not depend on customer identity) Refs TRAC-293 Co-authored-by: Claude --- .changeset/fix-customer-restricted-routes.md | 5 + .../webpages/[id]/contact/page-data.ts | 5 +- .../(default)/webpages/[id]/contact/page.tsx | 40 ++- .../webpages/[id]/normal/page-data.ts | 5 +- .../(default)/webpages/[id]/normal/page.tsx | 20 +- core/proxies/with-routes.ts | 239 ++++++++++-------- 6 files changed, 181 insertions(+), 133 deletions(-) create mode 100644 .changeset/fix-customer-restricted-routes.md diff --git a/.changeset/fix-customer-restricted-routes.md b/.changeset/fix-customer-restricted-routes.md new file mode 100644 index 0000000000..af8ca42c4d --- /dev/null +++ b/.changeset/fix-customer-restricted-routes.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Pass the customer access token through route resolution and the normal/contact webpage queries so customer-restricted web pages are accessible (and appear in navigation) for authenticated customers. The `with-routes` proxy is now wrapped in `auth()`, and webpage `page-data` queries switch to an uncached fetch when a customer token is present. diff --git a/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts b/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts index 191e5f56ac..4be07c89af 100644 --- a/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts @@ -31,11 +31,12 @@ const ContactPageQuery = graphql( type Variables = VariablesOf; -export const getWebpageData = cache(async (variables: Variables) => { +export const getWebpageData = cache(async (variables: Variables, customerAccessToken?: string) => { const { data } = await client.fetch({ document: ContactPageQuery, variables, - fetchOptions: { next: { revalidate } }, + customerAccessToken, + fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, }); return data; diff --git a/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx b/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx index 2c8896c405..2ec7f7b220 100644 --- a/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx +++ b/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx @@ -8,6 +8,7 @@ import type { Field, FieldGroup } from '@/vibes/soul/form/dynamic-form/schema'; import { Streamable } from '@/vibes/soul/lib/streamable'; import { ButtonLink } from '@/vibes/soul/primitives/button-link'; import { Breadcrumb } from '@/vibes/soul/sections/breadcrumbs'; +import { getSessionCustomerAccessToken } from '~/auth'; import { breadcrumbsTransformer, truncateBreadcrumbs, @@ -41,8 +42,8 @@ const fieldMapping = { type ContactField = keyof typeof fieldMapping; -const getWebPage = cache(async (id: string): Promise => { - const data = await getWebpageData({ id: decodeURIComponent(id) }); +const getWebPage = cache(async (id: string, customerAccessToken?: string): Promise => { + const data = await getWebpageData({ id: decodeURIComponent(id) }, customerAccessToken); const webpage = data.node?.__typename === 'ContactPage' ? data.node : null; if (!webpage) { @@ -62,10 +63,13 @@ const getWebPage = cache(async (id: string): Promise => { }; }); -async function getWebPageBreadcrumbs(id: string): Promise { +async function getWebPageBreadcrumbs( + id: string, + customerAccessToken?: string, +): Promise { const t = await getTranslations('WebPages.ContactUs'); - const webpage = await getWebPage(id); + const webpage = await getWebPage(id, customerAccessToken); const [, ...rest] = webpage.breadcrumbs.reverse(); const breadcrumbs = [ { @@ -82,8 +86,12 @@ async function getWebPageBreadcrumbs(id: string): Promise { return truncateBreadcrumbs(breadcrumbs, 5); } -async function getWebPageWithSuccessContent(id: string, message: string) { - const webpage = await getWebPage(id); +async function getWebPageWithSuccessContent( + id: string, + message: string, + customerAccessToken?: string, +) { + const webpage = await getWebPage(id, customerAccessToken); return { ...webpage, @@ -91,9 +99,9 @@ async function getWebPageWithSuccessContent(id: string, message: string) { }; } -async function getContactFields(id: string) { +async function getContactFields(id: string, customerAccessToken?: string) { const t = await getTranslations('WebPages.ContactUs.Form'); - const { entityId, path, contactFields } = await getWebPage(id); + const { entityId, path, contactFields } = await getWebPage(id, customerAccessToken); const toGroupsOfTwo = (fields: Field[]) => fields.reduce>>((acc, _, i) => { if (i % 2 === 0) { @@ -156,7 +164,8 @@ async function getContactFields(id: string) { export async function generateMetadata({ params }: Props): Promise { const { id, locale } = await params; - const webpage = await getWebPage(id); + const customerAccessToken = await getSessionCustomerAccessToken(); + const webpage = await getWebPage(id, customerAccessToken); const { pageTitle, metaDescription, metaKeywords } = webpage.seo; return { @@ -172,6 +181,7 @@ export async function generateMetadata({ params }: Props): Promise { export default async function ContactPage({ params, searchParams }: Props) { const { id, locale } = await params; const { success } = await searchParams; + const customerAccessToken = await getSessionCustomerAccessToken(); setRequestLocale(locale); @@ -180,8 +190,10 @@ export default async function ContactPage({ params, searchParams }: Props) { if (success === 'true') { return ( getWebPageBreadcrumbs(id))} - webPage={Streamable.from(() => getWebPageWithSuccessContent(id, t('success')))} + breadcrumbs={Streamable.from(() => getWebPageBreadcrumbs(id, customerAccessToken))} + webPage={Streamable.from(() => + getWebPageWithSuccessContent(id, t('success'), customerAccessToken), + )} > getWebPageBreadcrumbs(id))} - webPage={Streamable.from(() => getWebPage(id))} + breadcrumbs={Streamable.from(() => getWebPageBreadcrumbs(id, customerAccessToken))} + webPage={Streamable.from(() => getWebPage(id, customerAccessToken))} >
diff --git a/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts b/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts index eb87a7884d..43224103d5 100644 --- a/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts @@ -29,11 +29,12 @@ const NormalPageQuery = graphql( type Variables = VariablesOf; -export const getWebpageData = cache(async (variables: Variables) => { +export const getWebpageData = cache(async (variables: Variables, customerAccessToken?: string) => { const { data } = await client.fetch({ document: NormalPageQuery, variables, - fetchOptions: { next: { revalidate } }, + customerAccessToken, + fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, }); return data; diff --git a/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx b/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx index a222ea18c8..cde1916804 100644 --- a/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx +++ b/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx @@ -5,6 +5,7 @@ import { cache } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; import { Breadcrumb } from '@/vibes/soul/sections/breadcrumbs'; +import { getSessionCustomerAccessToken } from '~/auth'; import { breadcrumbsTransformer, truncateBreadcrumbs, @@ -19,8 +20,8 @@ interface Props { params: Promise<{ locale: string; id: string }>; } -const getWebPage = cache(async (id: string): Promise => { - const data = await getWebpageData({ id: decodeURIComponent(id) }); +const getWebPage = cache(async (id: string, customerAccessToken?: string): Promise => { + const data = await getWebpageData({ id: decodeURIComponent(id) }, customerAccessToken); const webpage = data.node?.__typename === 'NormalPage' ? data.node : null; if (!webpage) { @@ -37,10 +38,13 @@ const getWebPage = cache(async (id: string): Promise => { }; }); -async function getWebPageBreadcrumbs(id: string): Promise { +async function getWebPageBreadcrumbs( + id: string, + customerAccessToken?: string, +): Promise { const t = await getTranslations('WebPages.Normal'); - const webpage = await getWebPage(id); + const webpage = await getWebPage(id, customerAccessToken); const [, ...rest] = webpage.breadcrumbs.reverse(); const breadcrumbs = [ { @@ -59,7 +63,8 @@ async function getWebPageBreadcrumbs(id: string): Promise { export async function generateMetadata({ params }: Props): Promise { const { id, locale } = await params; - const webpage = await getWebPage(id); + const customerAccessToken = await getSessionCustomerAccessToken(); + const webpage = await getWebPage(id, customerAccessToken); const { pageTitle, metaDescription, metaKeywords } = webpage.seo; // Get the path from the last breadcrumb @@ -75,13 +80,14 @@ export async function generateMetadata({ params }: Props): Promise { export default async function WebPage({ params }: Props) { const { locale, id } = await params; + const customerAccessToken = await getSessionCustomerAccessToken(); setRequestLocale(locale); return ( getWebPageBreadcrumbs(id))} - webPage={Streamable.from(() => getWebPage(id))} + breadcrumbs={Streamable.from(() => getWebPageBreadcrumbs(id, customerAccessToken))} + webPage={Streamable.from(() => getWebPage(id, customerAccessToken))} /> ); } diff --git a/core/proxies/with-routes.ts b/core/proxies/with-routes.ts index 5e8d6901e1..2be0083849 100644 --- a/core/proxies/with-routes.ts +++ b/core/proxies/with-routes.ts @@ -1,6 +1,7 @@ import { NextFetchEvent, NextRequest, NextResponse } from 'next/server'; import { z } from 'zod'; +import { auth } from '~/auth'; import { client } from '~/client'; import { graphql } from '~/client/graphql'; import { revalidate } from '~/client/revalidate-target'; @@ -64,10 +65,11 @@ const GetRouteQuery = graphql(` } `); -const getRoute = async (path: string, channelId?: string) => { +const getRoute = async (path: string, channelId?: string, customerAccessToken?: string) => { const response = await client.fetch({ document: GetRouteQuery, variables: { path }, + customerAccessToken, fetchOptions: { next: { revalidate } }, channelId, }); @@ -86,10 +88,12 @@ const getRawWebPageContentQuery = graphql(` } `); -const getRawWebPageContent = async (id: string) => { +const getRawWebPageContent = async (id: string, customerAccessToken?: string) => { const response = await client.fetch({ document: getRawWebPageContentQuery, variables: { id }, + fetchOptions: { next: { revalidate } }, + customerAccessToken, }); const node = response.data.node; @@ -240,7 +244,11 @@ function normalizeForCompare(url: URL): string { const sameInternalUrl = (a: URL, b: URL) => a.origin === b.origin && normalizeForCompare(a) === normalizeForCompare(b); -const getRouteInfo = async (request: NextRequest, event: NextFetchEvent) => { +const getRouteInfo = async ( + request: NextRequest, + event: NextFetchEvent, + customerAccessToken?: string, +) => { const locale = request.headers.get('x-bc-locale') ?? ''; const channelId = request.headers.get('x-bc-channel-id') ?? ''; @@ -261,6 +269,19 @@ const getRouteInfo = async (request: NextRequest, event: NextFetchEvent) => { statusCache = await updateStatusCache(channelId, event); } + const parsedStatus = StorefrontStatusCacheSchema.safeParse(statusCache); + const status = parsedStatus.success ? parsedStatus.data.status : undefined; + + // The KV route cache is shared across customers and isn't namespaced by + // identity. Authenticated requests bypass it entirely so customer-specific + // route resolutions can't leak across users in either direction. + if (customerAccessToken) { + return { + route: await getRoute(pathname, channelId, customerAccessToken), + status, + }; + } + if (routeCache && routeCache.expiryTime < Date.now()) { event.waitUntil(updateRouteCache(pathname, channelId, event)); } else if (!routeCache) { @@ -268,11 +289,10 @@ const getRouteInfo = async (request: NextRequest, event: NextFetchEvent) => { } const parsedRoute = RouteCacheSchema.safeParse(routeCache); - const parsedStatus = StorefrontStatusCacheSchema.safeParse(statusCache); return { route: parsedRoute.success ? parsedRoute.data.route : undefined, - status: parsedStatus.success ? parsedStatus.data.status : undefined, + status, }; } catch (error) { // eslint-disable-next-line no-console @@ -286,142 +306,145 @@ const getRouteInfo = async (request: NextRequest, event: NextFetchEvent) => { }; export const withRoutes: ProxyFactory = () => { - // eslint-disable-next-line complexity - return async (request, event) => { - const locale = request.headers.get('x-bc-locale') ?? ''; + return (request, event) => + // eslint-disable-next-line complexity + auth(async (req) => { + const locale = req.headers.get('x-bc-locale') ?? ''; + const customerAccessToken = req.auth?.user?.customerAccessToken; - const { route, status } = await getRouteInfo(request, event); + const { route, status } = await getRouteInfo(req, event, customerAccessToken); - if (status === 'MAINTENANCE') { - // 503 status code not working - https://github.com/vercel/next.js/issues/50155 - return NextResponse.rewrite(new URL(`/${locale}/maintenance`, request.url), { status: 503 }); - } + if (status === 'MAINTENANCE') { + // 503 status code not working - https://github.com/vercel/next.js/issues/50155 + return NextResponse.rewrite(new URL(`/${locale}/maintenance`, req.url), { status: 503 }); + } - const redirectConfig = { - // Use 301 status code as it is more universally supported by crawlers - status: 301, - nextConfig: { - // Preserve the trailing slash if it was present in the original URL - // BigCommerce by default returns the trailing slash. - trailingSlash: process.env.TRAILING_SLASH !== 'false', - }, - }; + const redirectConfig = { + // Use 301 status code as it is more universally supported by crawlers + status: 301, + nextConfig: { + // Preserve the trailing slash if it was present in the original URL + // BigCommerce by default returns the trailing slash. + trailingSlash: process.env.TRAILING_SLASH !== 'false', + }, + }; + + if (route?.redirect) { + // Only carry over query params if the fromPath does not have any, as Bigcommerce 301 redirects support matching by specific query params. + const fromPathSearchParams = new URL(route.redirect.fromPath, req.url).search; + const searchParams = fromPathSearchParams.length > 0 ? '' : req.nextUrl.search; + + switch (route.redirect.to.__typename) { + case 'BlogPostRedirect': + case 'BrandRedirect': + case 'CategoryRedirect': + case 'PageRedirect': + case 'ProductRedirect': { + // For dynamic redirects, assume an internal redirect and construct the URL from the path + const redirectUrl = new URL(route.redirect.to.path + searchParams, req.url); + + if (sameInternalUrl(req.nextUrl, redirectUrl)) { + break; + } - if (route?.redirect) { - // Only carry over query params if the fromPath does not have any, as Bigcommerce 301 redirects support matching by specific query params. - const fromPathSearchParams = new URL(route.redirect.fromPath, request.url).search; - const searchParams = fromPathSearchParams.length > 0 ? '' : request.nextUrl.search; - - switch (route.redirect.to.__typename) { - case 'BlogPostRedirect': - case 'BrandRedirect': - case 'CategoryRedirect': - case 'PageRedirect': - case 'ProductRedirect': { - // For dynamic redirects, assume an internal redirect and construct the URL from the path - const redirectUrl = new URL(route.redirect.to.path + searchParams, request.url); - - if (sameInternalUrl(request.nextUrl, redirectUrl)) { - break; + return NextResponse.redirect(redirectUrl, redirectConfig); } - return NextResponse.redirect(redirectUrl, redirectConfig); - } - - case 'ManualRedirect': { - // For manual redirects, to.url will be a relative path if it is an internal redirect and an absolute URL if it is an external redirect. - // URL constructor will correctly handle both cases. - // If the manual redirect is an external URL, we should not carry query params. - const redirectUrl = new URL(route.redirect.to.url, request.url); + case 'ManualRedirect': { + // For manual redirects, to.url will be a relative path if it is an internal redirect and an absolute URL if it is an external redirect. + // URL constructor will correctly handle both cases. + // If the manual redirect is an external URL, we should not carry query params. + const redirectUrl = new URL(route.redirect.to.url, req.url); - if (redirectUrl.origin === request.nextUrl.origin) { - redirectUrl.search = searchParams; + if (redirectUrl.origin === req.nextUrl.origin) { + redirectUrl.search = searchParams; - if (sameInternalUrl(request.nextUrl, redirectUrl)) { - break; + if (sameInternalUrl(req.nextUrl, redirectUrl)) { + break; + } } - } - return NextResponse.redirect(redirectUrl, redirectConfig); - } + return NextResponse.redirect(redirectUrl, redirectConfig); + } - default: { - // If for some reason the redirect type is not recognized, use the toUrl as a fallback - return NextResponse.redirect(route.redirect.toUrl, redirectConfig); + default: { + // If for some reason the redirect type is not recognized, use the toUrl as a fallback + return NextResponse.redirect(route.redirect.toUrl, redirectConfig); + } } } - } - const node = route?.node; - let url: string; + const node = route?.node; + let url: string; - switch (node?.__typename) { - case 'Brand': { - url = `/${locale}/brand/${node.entityId}`; - break; - } + switch (node?.__typename) { + case 'Brand': { + url = `/${locale}/brand/${node.entityId}`; + break; + } - case 'Category': { - url = `/${locale}/category/${node.entityId}`; - break; - } + case 'Category': { + url = `/${locale}/category/${node.entityId}`; + break; + } - case 'Product': { - url = `/${locale}/product/${node.entityId}`; + case 'Product': { + url = `/${locale}/product/${node.entityId}`; - const isPrefetch = request.headers.get('Next-Router-Prefetch') === '1'; - const isRSC = request.headers.get('RSC') === '1'; + const isPrefetch = req.headers.get('Next-Router-Prefetch') === '1'; + const isRSC = req.headers.get('RSC') === '1'; - if (!isPrefetch && !isRSC) { - event.waitUntil(recordProductVisit(request, node.entityId)); - } + if (!isPrefetch && !isRSC) { + event.waitUntil(recordProductVisit(req, node.entityId)); + } - break; - } + break; + } - case 'NormalPage': { - url = `/${locale}/webpages/${node.id}/normal/`; - break; - } + case 'NormalPage': { + url = `/${locale}/webpages/${node.id}/normal/`; + break; + } - case 'ContactPage': { - url = `/${locale}/webpages/${node.id}/contact/`; - break; - } + case 'ContactPage': { + url = `/${locale}/webpages/${node.id}/contact/`; + break; + } - case 'RawHtmlPage': { - const { htmlBody } = await getRawWebPageContent(node.id); + case 'RawHtmlPage': { + const { htmlBody } = await getRawWebPageContent(node.id, customerAccessToken); - return new NextResponse(htmlBody, { - headers: { 'content-type': 'text/html' }, - }); - } + return new NextResponse(htmlBody, { + headers: { 'content-type': 'text/html' }, + }); + } - case 'Blog': { - url = `/${locale}/blog`; - break; - } + case 'Blog': { + url = `/${locale}/blog`; + break; + } - case 'BlogPost': { - url = `/${locale}/blog/${node.entityId}`; - break; - } + case 'BlogPost': { + url = `/${locale}/blog/${node.entityId}`; + break; + } - default: { - const { pathname } = new URL(request.url); + default: { + const { pathname } = new URL(req.url); - const cleanPathName = clearLocaleFromPath(pathname, locale); + const cleanPathName = clearLocaleFromPath(pathname, locale); - url = `/${locale}${cleanPathName}`; + url = `/${locale}${cleanPathName}`; + } } - } - const rewriteUrl = new URL(url, request.url); + const rewriteUrl = new URL(url, req.url); - rewriteUrl.search = request.nextUrl.search; + rewriteUrl.search = req.nextUrl.search; - return NextResponse.rewrite(rewriteUrl); - }; + return NextResponse.rewrite(rewriteUrl); + // @ts-expect-error auth() overload expects middleware return type, but we return NextResponse directly for the proxy + })(request, event); }; async function recordProductVisit(request: Request, productId: number) { From d00beeb458e720070c190c09ee26ea50802b1659 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Fri, 15 May 2026 09:33:36 -0600 Subject: [PATCH 40/47] fix(core): TRAC-281 prevent breadcrumb cache mutation and stabilize flaky E2E tests (#2964) Fix the underlying TRAC-281 breadcrumb mutation bug and stabilize the specific E2E tests that block CI around it. Core fixes: - `breadcrumbs-transformer.ts`: stop calling `.reverse()` on the array returned from React's `cache()`, which mutated the shared reference and caused parent breadcrumbs to disappear when `generateMetadata` raced `getWebPageBreadcrumbs`. Fix off-by-one in `truncateBreadcrumbs` where arrays exactly at the target length were incorrectly truncated. - `product-review-schema.tsx`: defer DOMPurify-using markup to the client via a mounted-state check; DOMPurify needs a browser DOM and crashed during SSR. E2E test stabilization: - `webpages.spec.ts`: drop the truncated-breadcrumb assertion from the nested-webpages test; the Storefront API caches PageTree and the assertion is unreliable in CI even after the upstream PHP fix. - `cart.spec.ts`, `coupon.spec.ts`, `shipping.spec.ts` (helper): stop asserting on the add-to-cart Sonner toast, which auto-dismisses after ~4s and made the assertion racy. Wait for `networkidle` and verify state on the /cart page instead. - `coupon.spec.ts`: replace the catch/reload pattern with a `toPass` retry that re-applies the coupon from a clean reloaded state when the optimistic update reverts (CATALYST-1685). The previous pattern only recovered when the server had already applied the coupon; reload alone couldn't recover a silently-failed action. - `account/orders.spec.ts`: add `.first()` to the empty-state title and order-id assertions to match the pattern already used by the rest of the file; Next.js 16.2 PPR/Suspense leaves a hidden stale shell alongside the streamed content, leaving two matches in the DOM. CI workflow: - `e2e.yml`: hoist `TESTS_LOCALE` and `TRAILING_SLASH` to job-level env so every step (Build, Start server, Run E2E tests) receives them. Previously they were only set on Start server, so: 1. The Build step ran without `TRAILING_SLASH`, baking `trailingSlash: true` into `next.config.ts` for the TRAILING_SLASH=false matrix. Next's own routing then added the trailing slash before the proxy could intercept, causing the trailing-slash redirect-loop regression tests to fail when they finally ran. 2. The Run E2E tests step ran without `TESTS_LOCALE` or `TRAILING_SLASH`, so `testEnv` fell back to schema defaults and every tagged test in the alternate-locale and TRAILING_SLASH=false matrices self-skipped, silently making those matrix jobs no-ops since they were added in the Next.js 16 proxy migration (#2912). Fixes TRAC-281 Refs CATALYST-1685 Co-authored-by: Claude --- .changeset/fix-breadcrumb-cache-mutation.md | 5 ++ .github/workflows/e2e.yml | 6 ++- .../product-review-schema.tsx | 15 +++++- .../(default)/webpages/[id]/contact/page.tsx | 2 +- .../(default)/webpages/[id]/normal/page.tsx | 2 +- .../breadcrumbs-transformer.ts | 2 +- core/tests/ui/e2e/account/orders.spec.ts | 4 +- core/tests/ui/e2e/cart.spec.ts | 11 ++-- core/tests/ui/e2e/coupon.spec.ts | 54 +++++++++---------- core/tests/ui/e2e/shipping.spec.ts | 11 ++-- core/tests/ui/e2e/webpages.spec.ts | 11 +--- 11 files changed, 62 insertions(+), 61 deletions(-) create mode 100644 .changeset/fix-breadcrumb-cache-mutation.md diff --git a/.changeset/fix-breadcrumb-cache-mutation.md b/.changeset/fix-breadcrumb-cache-mutation.md new file mode 100644 index 0000000000..4730ef3faa --- /dev/null +++ b/.changeset/fix-breadcrumb-cache-mutation.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Prevent breadcrumb array mutation on cached web pages by spreading the React `cache()` result before reversing, and fix an off-by-one in `truncateBreadcrumbs` that incorrectly truncated arrays exactly at the target length. Also defer `ProductReviewSchema` to client-only rendering to avoid a DOMPurify SSR crash. diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 657f562574..8da3f6f823 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -51,6 +51,10 @@ jobs: locale-var: TESTS_ALTERNATE_LOCALE artifact-name: playwright-report-alternate-locale + env: + TESTS_LOCALE: ${{ vars[matrix.locale-var] }} + TRAILING_SLASH: ${{ matrix.trailing-slash }} + steps: - name: Checkout code uses: actions/checkout@v4 @@ -86,8 +90,6 @@ jobs: AUTH_SECRET: ${{ secrets.TESTS_AUTH_SECRET }} AUTH_TRUST_HOST: ${{ vars.TESTS_AUTH_TRUST_HOST }} BIGCOMMERCE_TRUSTED_PROXY_SECRET: ${{ secrets.BIGCOMMERCE_TRUSTED_PROXY_SECRET }} - TESTS_LOCALE: ${{ vars[matrix.locale-var] }} - TRAILING_SLASH: ${{ matrix.trailing-slash }} DEFAULT_REVALIDATE_TARGET: ${{ matrix.name == 'default' && '1' || '' }} - name: Run E2E tests diff --git a/core/app/[locale]/(default)/product/[slug]/_components/product-review-schema/product-review-schema.tsx b/core/app/[locale]/(default)/product/[slug]/_components/product-review-schema/product-review-schema.tsx index 21917a35e8..1a6ccc3c7b 100644 --- a/core/app/[locale]/(default)/product/[slug]/_components/product-review-schema/product-review-schema.tsx +++ b/core/app/[locale]/(default)/product/[slug]/_components/product-review-schema/product-review-schema.tsx @@ -3,6 +3,7 @@ // eslint-disable-next-line import/no-named-as-default import DOMPurify from 'dompurify'; import { useFormatter } from 'next-intl'; +import { useEffect, useState } from 'react'; import { Product as ProductSchemaType, WithContext } from 'schema-dts'; import { FragmentOf } from '~/client/graphql'; @@ -16,6 +17,16 @@ interface Props { export const ProductReviewSchema = ({ reviews, productId }: Props) => { const format = useFormatter(); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + // DOMPurify requires a browser DOM, so we skip SSR and only render on the client. + if (!mounted) { + return null; + } const productReviewSchema: WithContext = { '@context': 'https://schema.org', @@ -43,7 +54,9 @@ export const ProductReviewSchema = ({ reviews, productId }: Props) => { return (