From 4ca18e2eb68aca558f0b9a98986fbb5db0435dc2 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 3 Mar 2026 11:36:38 -0600 Subject: [PATCH 01/24] refactor(core): use dynamic imports in client to avoid AsyncLocalStorage poisoning Replace static imports of next/headers, next/navigation, and next-intl/server with dynamic import() calls inside the hooks that use them. Static imports cause these modules to be evaluated during module graph resolution when next.config.ts imports this file, poisoning the process-wide AsyncLocalStorage context. Dynamic imports defer module loading to call time, after Next.js has fully initialized. --- core/client/index.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/core/client/index.ts b/core/client/index.ts index d0b059b994..51020b0053 100644 --- a/core/client/index.ts +++ b/core/client/index.ts @@ -1,22 +1,30 @@ import { BigCommerceAuthError, createClient } from '@bigcommerce/catalyst-client'; -import { headers } from 'next/headers'; -// eslint-disable-next-line @typescript-eslint/no-restricted-imports -import { redirect } from 'next/navigation'; -import { getLocale as getServerLocale } from 'next-intl/server'; import { getChannelIdFromLocale } from '../channels.config'; import { backendUserAgent } from '../user-agent'; +// next/headers, next/navigation, and next-intl/server are imported dynamically +// (via `import()`) rather than statically. Static imports cause these modules to +// be evaluated during module graph resolution when next.config.ts imports this +// file, which poisons the process-wide AsyncLocalStorage context (pnpm symlinks +// create two separate singleton instances of next/headers). Dynamic imports +// defer module loading to call time, after Next.js has fully initialized. +// +// During config resolution, the dynamic import of next-intl/server succeeds but +// getLocale() throws ("not supported in Client Components") — the try/catch +// below absorbs this gracefully, and getChannelId falls back to defaultChannelId. + const getLocale = async () => { try { - const locale = await getServerLocale(); + const { getLocale: getServerLocale } = await import('next-intl/server'); - return locale; + return await getServerLocale(); } catch { /** * Next-intl `getLocale` only works on the server, and when middleware has run. * * Instances when `getLocale` will not work: + * - Requests during next.config.ts resolution * - Requests in middlewares * - Requests in `generateStaticParams` * - Request in api routes @@ -45,6 +53,7 @@ export const client = createClient({ const locale = await getLocale(); if (fetchOptions?.cache && ['no-store', 'no-cache'].includes(fetchOptions.cache)) { + const { headers } = await import('next/headers'); const ipAddress = (await headers()).get('X-Forwarded-For'); if (ipAddress) { @@ -61,8 +70,10 @@ export const client = createClient({ headers: requestHeaders, }; }, - onError: (error, queryType) => { + onError: async (error, queryType) => { if (error instanceof BigCommerceAuthError && queryType === 'query') { + const { redirect } = await import('next/navigation'); + redirect('/api/auth/signout'); } }, From fbf8169b33db5db30afa6e38e19cf97c340b7a78 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 24 Feb 2026 16:27:53 -0600 Subject: [PATCH 02/24] chore(core): bump next.js to 16 and align peer deps Upgrade next, @next/bundle-analyzer, eslint-config-next to ^16.1.0 and @next/eslint-plugin-next to ^16.1.0. React 19.1.5 is already compatible. --- core/package.json | 6 +- pnpm-lock.yaml | 1417 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 1162 insertions(+), 261 deletions(-) diff --git a/core/package.json b/core/package.json index 30f5af80e5..35723752a1 100644 --- a/core/package.json +++ b/core/package.json @@ -57,9 +57,9 @@ "lodash.debounce": "^4.0.8", "lru-cache": "^11.1.0", "lucide-react": "^0.474.0", - "next": "15.5.10", + "next": "^16.1.6", "next-auth": "5.0.0-beta.30", - "next-intl": "^4.1.0", + "next-intl": "^4.6.1", "nuqs": "^2.4.3", "p-lazy": "^5.0.0", "react": "19.1.5", @@ -79,7 +79,7 @@ "@bigcommerce/eslint-config-catalyst": "workspace:^", "@faker-js/faker": "^9.8.0", "@gql.tada/cli-utils": "^1.6.3", - "@next/bundle-analyzer": "15.5.10", + "@next/bundle-analyzer": "^16.1.6", "@playwright/test": "^1.52.0", "@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/typography": "^0.5.16", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f7dd24ad67..554b841cac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,7 +43,7 @@ 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@15.5.10(@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.11.31)(@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.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) '@conform-to/react': specifier: ^1.6.1 version: 1.6.1(react@19.1.5) @@ -115,7 +115,7 @@ importers: version: 1.35.0 '@vercel/analytics': specifier: ^1.5.0 - version: 1.5.0(next@15.5.10(@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.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/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@15.5.10(@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.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)) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -168,17 +168,17 @@ importers: specifier: ^0.474.0 version: 0.474.0(react@19.1.5) next: - specifier: 15.5.10 - version: 15.5.10(@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.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 - version: 5.0.0-beta.30(next@15.5.10(@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.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-intl: - specifier: ^4.1.0 - version: 4.1.0(next@15.5.10(@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) + 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) nuqs: specifier: ^2.4.3 - version: 2.4.3(next@15.5.10(@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.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) p-lazy: specifier: ^5.0.0 version: 5.0.0 @@ -205,7 +205,7 @@ importers: version: 1.7.4(react-dom@19.1.5(react@19.1.5))(react@19.1.5) tailwindcss-radix: specifier: ^3.0.5 - version: 3.0.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) + 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))) uuid: specifier: ^11.1.0 version: 11.1.0 @@ -218,7 +218,7 @@ importers: version: 1.12.16(graphql@16.11.0)(typescript@5.8.3) '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(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) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../packages/eslint-config-catalyst @@ -229,17 +229,17 @@ importers: specifier: ^1.6.3 version: 1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.11.0)(typescript@5.8.3))(graphql@16.11.0)(typescript@5.8.3) '@next/bundle-analyzer': - specifier: 15.5.10 - version: 15.5.10 + specifier: ^16.1.6 + version: 16.1.6 '@playwright/test': specifier: ^1.52.0 version: 1.52.0 '@tailwindcss/container-queries': specifier: ^0.1.1 - version: 0.1.1(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) + version: 0.1.1(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3))) '@tailwindcss/typography': specifier: ^0.5.16 - version: 0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) + version: 0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3))) '@types/gtag.js': specifier: ^0.0.20 version: 0.0.20 @@ -290,10 +290,10 @@ importers: version: 0.6.12(prettier@3.6.2) tailwindcss: specifier: ^3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)) tailwindcss-animate: specifier: 1.0.7 - version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) + version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3))) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -333,7 +333,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(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) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -363,7 +363,7 @@ importers: version: 3.6.2 tsup: specifier: ^8.5.0 - version: 8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(@swc/core@1.15.18)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -382,7 +382,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(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) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -400,7 +400,7 @@ importers: version: 3.6.2 tsup: specifier: ^8.5.0 - version: 8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(@swc/core@1.15.18)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -533,10 +533,10 @@ importers: dependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(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) '@next/eslint-plugin-next': specifier: ^15.3.3 - version: 15.3.3 + version: 15.5.12 eslint-config-prettier: specifier: ^10.1.5 version: 10.1.5(eslint@8.57.1) @@ -1553,6 +1553,9 @@ packages: '@emnapi/runtime@1.4.5': resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@emnapi/wasi-threads@1.0.1': resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} @@ -1872,10 +1875,20 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/regexpp@4.12.1': resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1906,21 +1919,33 @@ packages: '@formatjs/ecma402-abstract@2.3.4': resolution: {integrity: sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==} + '@formatjs/ecma402-abstract@3.1.1': + resolution: {integrity: sha512-jhZbTwda+2tcNrs4kKvxrPLPjx8QsBCLCUgrrJ/S+G9YrGHWLhAyFMMBHJBnBoOwuLHd7L14FgYudviKaxkO2Q==} + '@formatjs/fast-memoize@2.2.7': resolution: {integrity: sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==} + '@formatjs/fast-memoize@3.1.0': + resolution: {integrity: sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg==} + '@formatjs/icu-messageformat-parser@2.11.2': resolution: {integrity: sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA==} + '@formatjs/icu-messageformat-parser@3.5.1': + resolution: {integrity: sha512-sSDmSvmmoVQ92XqWb499KrIhv/vLisJU8ITFrx7T7NZHUmMY7EL9xgRowAosaljhqnj/5iufG24QrdzB6X3ItA==} + '@formatjs/icu-skeleton-parser@1.8.14': resolution: {integrity: sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ==} - '@formatjs/intl-localematcher@0.5.10': - resolution: {integrity: sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==} + '@formatjs/icu-skeleton-parser@2.1.1': + resolution: {integrity: sha512-PSFABlcNefjI6yyk8f7nyX1DC7NHmq6WaCHZLySEXBrXuLOB2f935YsnzuPjlz+ibhb9yWTdPeVX1OVcj24w2Q==} '@formatjs/intl-localematcher@0.6.1': resolution: {integrity: sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==} + '@formatjs/intl-localematcher@0.8.1': + resolution: {integrity: sha512-xwEuwQFdtSq1UKtQnyTZWC+eHdv7Uygoa+H2k/9uzBVQjDyp9r20LNDNKedWXll7FssT3GRHvqsdJGYSUWqYFA==} + '@gql.tada/cli-utils@1.6.3': resolution: {integrity: sha512-jFFSY8OxYeBxdKi58UzeMXG1tdm4FVjXa8WHIi66Gzu9JWtCE6mqom3a8xkmSw+mVaybFW5EN2WXf1WztJVNyQ==} peerDependencies: @@ -1977,14 +2002,18 @@ packages: peerDependencies: react: ^16.13 || ^17 || ^18 || ^19 + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-arm64@0.34.3': - resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] @@ -1995,8 +2024,8 @@ packages: cpu: [x64] os: [darwin] - '@img/sharp-darwin-x64@0.34.3': - resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] @@ -2006,8 +2035,8 @@ packages: cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.0': - resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] @@ -2016,8 +2045,8 @@ packages: cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.0': - resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] @@ -2026,8 +2055,8 @@ packages: cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm64@1.2.0': - resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] @@ -2036,23 +2065,28 @@ packages: cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-arm@1.2.0': - resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-ppc64@1.2.0': - resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.0': - resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] @@ -2061,8 +2095,8 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-libvips-linux-x64@1.2.0': - resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] @@ -2071,8 +2105,8 @@ packages: cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] @@ -2081,8 +2115,8 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] @@ -2092,8 +2126,8 @@ packages: cpu: [arm64] os: [linux] - '@img/sharp-linux-arm64@0.34.3': - resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] @@ -2104,26 +2138,32 @@ packages: cpu: [arm] os: [linux] - '@img/sharp-linux-arm@0.34.3': - resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-ppc64@0.34.3': - resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-s390x@0.34.3': - resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] @@ -2134,8 +2174,8 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-linux-x64@0.34.3': - resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] @@ -2146,8 +2186,8 @@ packages: cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.3': - resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] @@ -2158,8 +2198,8 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.3': - resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] @@ -2169,13 +2209,13 @@ packages: engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-wasm32@0.34.3': - resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.3': - resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] @@ -2186,8 +2226,8 @@ packages: cpu: [ia32] os: [win32] - '@img/sharp-win32-ia32@0.34.3': - resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] @@ -2198,8 +2238,8 @@ packages: cpu: [x64] os: [win32] - '@img/sharp-win32-x64@0.34.3': - resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -2470,62 +2510,62 @@ packages: '@napi-rs/wasm-runtime@0.2.7': resolution: {integrity: sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw==} - '@next/bundle-analyzer@15.5.10': - resolution: {integrity: sha512-yQk9mNbVtxZhVdaPlw42vOMl8lc7Xfr05SyhzhXsyI1tWjKaG5EWe1ASXyeSG2MQic2YTLrcJrX4UBCx2xHgNQ==} + '@next/bundle-analyzer@16.1.6': + resolution: {integrity: sha512-ee2kagdTaeEWPlotgdTOqFHYcD3e2m2bbE3I9Rq2i6ABYi5OgopmtEUe8NM23viaYxLV2tDH/2nd5+qKoEr6cw==} - '@next/env@15.5.10': - resolution: {integrity: sha512-plg+9A/KoZcTS26fe15LHg+QxReTazrIOoKKUC3Uz4leGGeNPgLHdevVraAAOX0snnUs3WkRx3eUQpj9mreG6A==} - - '@next/eslint-plugin-next@15.3.3': - resolution: {integrity: sha512-VKZJEiEdpKkfBmcokGjHu0vGDG+8CehGs90tBEy/IDoDDKGngeyIStt2MmE5FYNyU9BhgR7tybNWTAJY/30u+Q==} + '@next/env@16.1.6': + resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} '@next/eslint-plugin-next@15.5.10': resolution: {integrity: sha512-fDpxcy6G7Il4lQVVsaJD0fdC2/+SmuBGTF+edRLlsR4ZFOE3W2VyzrrGYdg/pHW8TydeAdSVM+mIzITGtZ3yWA==} - '@next/swc-darwin-arm64@15.5.7': - resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} + '@next/eslint-plugin-next@15.5.12': + resolution: {integrity: sha512-+ZRSDFTv4aC96aMb5E41rMjysx8ApkryevnvEYZvPZO52KvkqP5rNExLUXJFr9P4s0f3oqNQR6vopCZsPWKDcQ==} + + '@next/swc-darwin-arm64@16.1.6': + resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.5.7': - resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} + '@next/swc-darwin-x64@16.1.6': + resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.5.7': - resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} + '@next/swc-linux-arm64-gnu@16.1.6': + resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.5.7': - resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} + '@next/swc-linux-arm64-musl@16.1.6': + resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.5.7': - resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} + '@next/swc-linux-x64-gnu@16.1.6': + resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.5.7': - resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} + '@next/swc-linux-x64-musl@16.1.6': + resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.5.7': - resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} + '@next/swc-win32-arm64-msvc@16.1.6': + resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.5.7': - resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} + '@next/swc-win32-x64-msvc@16.1.6': + resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -4324,60 +4364,120 @@ packages: cpu: [arm64] os: [darwin] + '@swc/core-darwin-arm64@1.15.18': + resolution: {integrity: sha512-+mIv7uBuSaywN3C9LNuWaX1jJJ3SKfiJuE6Lr3bd+/1Iv8oMU7oLBjYMluX1UrEPzwN2qCdY6Io0yVicABoCwQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + '@swc/core-darwin-x64@1.11.31': resolution: {integrity: sha512-THSGaSwT96JwXDwuXQ6yFBbn+xDMdyw7OmBpnweAWsh5DhZmQkALEm1DgdQO3+rrE99MkmzwAfclc0UmYro/OA==} engines: {node: '>=10'} cpu: [x64] os: [darwin] + '@swc/core-darwin-x64@1.15.18': + resolution: {integrity: sha512-wZle0eaQhnzxWX5V/2kEOI6Z9vl/lTFEC6V4EWcn+5pDjhemCpQv9e/TDJ0GIoiClX8EDWRvuZwh+Z3dhL1NAg==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + '@swc/core-linux-arm-gnueabihf@1.11.31': resolution: {integrity: sha512-laKtQFnW7KHgE57Hx32os2SNAogcuIDxYE+3DYIOmDMqD7/1DCfJe6Rln2N9WcOw6HuDbDpyQavIwZNfSAa8vQ==} engines: {node: '>=10'} cpu: [arm] os: [linux] + '@swc/core-linux-arm-gnueabihf@1.15.18': + resolution: {integrity: sha512-ao61HGXVqrJFHAcPtF4/DegmwEkVCo4HApnotLU8ognfmU8x589z7+tcf3hU+qBiU1WOXV5fQX6W9Nzs6hjxDw==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + '@swc/core-linux-arm64-gnu@1.11.31': resolution: {integrity: sha512-T+vGw9aPE1YVyRxRr1n7NAdkbgzBzrXCCJ95xAZc/0+WUwmL77Z+js0J5v1KKTRxw4FvrslNCOXzMWrSLdwPSA==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + '@swc/core-linux-arm64-gnu@1.15.18': + resolution: {integrity: sha512-3xnctOBLIq3kj8PxOCgPrGjBLP/kNOddr6f5gukYt/1IZxsITQaU9TDyjeX6jG+FiCIHjCuWuffsyQDL5Ew1bg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + '@swc/core-linux-arm64-musl@1.11.31': resolution: {integrity: sha512-Mztp5NZkyd5MrOAG+kl+QSn0lL4Uawd4CK4J7wm97Hs44N9DHGIG5nOz7Qve1KZo407Y25lTxi/PqzPKHo61zQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + '@swc/core-linux-arm64-musl@1.15.18': + resolution: {integrity: sha512-0a+Lix+FSSHBSBOA0XznCcHo5/1nA6oLLjcnocvzXeqtdjnPb+SvchItHI+lfeiuj1sClYPDvPMLSLyXFaiIKw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + '@swc/core-linux-x64-gnu@1.11.31': resolution: {integrity: sha512-DDVE0LZcXOWwOqFU1Xi7gdtiUg3FHA0vbGb3trjWCuI1ZtDZHEQYL4M3/2FjqKZtIwASrDvO96w91okZbXhvMg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + '@swc/core-linux-x64-gnu@1.15.18': + resolution: {integrity: sha512-wG9J8vReUlpaHz4KOD/5UE1AUgirimU4UFT9oZmupUDEofxJKYb1mTA/DrMj0s78bkBiNI+7Fo2EgPuvOJfuAA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + '@swc/core-linux-x64-musl@1.11.31': resolution: {integrity: sha512-mJA1MzPPRIfaBUHZi0xJQ4vwL09MNWDeFtxXb0r4Yzpf0v5Lue9ymumcBPmw/h6TKWms+Non4+TDquAsweuKSw==} engines: {node: '>=10'} cpu: [x64] os: [linux] + '@swc/core-linux-x64-musl@1.15.18': + resolution: {integrity: sha512-4nwbVvCphKzicwNWRmvD5iBaZj8JYsRGa4xOxJmOyHlMDpsvvJ2OR2cODlvWyGFH6BYL1MfIAK3qph3hp0Az6g==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + '@swc/core-win32-arm64-msvc@1.11.31': resolution: {integrity: sha512-RdtakUkNVAb/FFIMw3LnfNdlH1/ep6KgiPDRlmyUfd0WdIQ3OACmeBegEFNFTzi7gEuzy2Yxg4LWf4IUVk8/bg==} engines: {node: '>=10'} cpu: [arm64] os: [win32] + '@swc/core-win32-arm64-msvc@1.15.18': + resolution: {integrity: sha512-zk0RYO+LjiBCat2RTMHzAWaMky0cra9loH4oRrLKLLNuL+jarxKLFDA8xTZWEkCPLjUTwlRN7d28eDLLMgtUcQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + '@swc/core-win32-ia32-msvc@1.11.31': resolution: {integrity: sha512-hErXdCGsg7swWdG1fossuL8542I59xV+all751mYlBoZ8kOghLSKObGQTkBbuNvc0sUKWfWg1X0iBuIhAYar+w==} engines: {node: '>=10'} cpu: [ia32] os: [win32] + '@swc/core-win32-ia32-msvc@1.15.18': + resolution: {integrity: sha512-yVuTrZ0RccD5+PEkpcLOBAuPbYBXS6rslENvIXfvJGXSdX5QGi1ehC4BjAMl5FkKLiam4kJECUI0l7Hq7T1vwg==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + '@swc/core-win32-x64-msvc@1.11.31': resolution: {integrity: sha512-5t7SGjUBMMhF9b5j17ml/f/498kiBJNf4vZFNM421UGUEETdtjPN9jZIuQrowBkoFGJTCVL/ECM4YRtTH30u/A==} engines: {node: '>=10'} cpu: [x64] os: [win32] + '@swc/core-win32-x64-msvc@1.15.18': + resolution: {integrity: sha512-7NRmE4hmUQNCbYU3Hn9Tz57mK9Qq4c97ZS+YlamlK6qG9Fb5g/BB3gPDe0iLlJkns/sYv2VWSkm8c3NmbEGjbg==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + '@swc/core@1.11.31': resolution: {integrity: sha512-mAby9aUnKRjMEA7v8cVZS9Ah4duoRBnX7X6r5qrhTxErx+68MoY1TPrVwj/66/SWN3Bl+jijqAqoB8Qx0QE34A==} engines: {node: '>=10'} @@ -4387,6 +4487,15 @@ packages: '@swc/helpers': optional: true + '@swc/core@1.15.18': + resolution: {integrity: sha512-z87aF9GphWp//fnkRsqvtY+inMVPgYW3zSlXH1kJFvRT5H/wiAn+G32qW5l3oEk63KSF1x3Ov0BfHCObAmT8RA==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -4402,6 +4511,9 @@ packages: '@swc/types@0.1.21': resolution: {integrity: sha512-2YEtj5HJVbKivud9N4bpPBAyZhj4S2Ipe5LkUG94alTpr7in/GU/EARgPAd3BwU+YOmFVJC2+kjqhGRi3r0ZpQ==} + '@swc/types@0.1.25': + resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} + '@szmarczak/http-timer@4.0.6': resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} @@ -4613,6 +4725,14 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/eslint-plugin@8.56.1': + resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.56.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser@8.28.0': resolution: {integrity: sha512-LPcw1yHD3ToaDEoljFEfQ9j2xShY367h7FZ1sq5NJT9I3yj4LHer1Xd1yRSOdYy9BpsrxU7R+eoDokChYM53lQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4620,10 +4740,33 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/parser@8.56.1': + resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.56.1': + resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/scope-manager@8.28.0': resolution: {integrity: sha512-u2oITX3BJwzWCapoZ/pXw6BCOl8rJP4Ij/3wPoGvY8XwvXflOzd1kLrDUUUAIEdJSFh+ASwdTHqtan9xSg8buw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.56.1': + resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.56.1': + resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/type-utils@8.28.0': resolution: {integrity: sha512-oRoXu2v0Rsy/VoOGhtWrOKDiIehvI+YNrDk5Oqj40Mwm0Yt01FC/Q7nFqg088d3yAsR1ZcZFVfPCTTFCe/KPwg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4631,16 +4774,33 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/type-utils@8.56.1': + resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/types@8.28.0': resolution: {integrity: sha512-bn4WS1bkKEjx7HqiwG2JNB3YJdC1q6Ue7GyGlwPHyt0TnVq6TtD/hiOdTZt71sq0s7UzqBFXD8t8o2e63tXgwA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.56.1': + resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.28.0': resolution: {integrity: sha512-H74nHEeBGeklctAVUvmDkxB1mk+PAZ9FiOMPFncdqeRBXxk1lWSYraHw8V12b7aa6Sg9HOBNbGdSHobBPuQSuA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/typescript-estree@8.56.1': + resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.28.0': resolution: {integrity: sha512-OELa9hbTYciYITqgurT1u/SzpQVtDLmQMFzy/N8pQE+tefOyCWT79jHsav294aTqV1q1u+VzqDGbuujvRYaeSQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4648,10 +4808,21 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/utils@8.56.1': + resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/visitor-keys@8.28.0': resolution: {integrity: sha512-hbn8SZ8w4u2pRwgQ1GlUrPKE+t2XvcCW5tTRF7j6SMYIuYG37XuzIW44JCZPa36evi0Oy2SnM664BlIaAuQcvg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.56.1': + resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} @@ -5042,6 +5213,10 @@ packages: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -5150,6 +5325,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + bare-events@2.5.4: resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} @@ -5186,6 +5365,11 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} + hasBin: true + basic-ftp@5.0.5: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} @@ -5224,6 +5408,10 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@5.0.3: + resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -5708,6 +5896,9 @@ packages: decimal.js@10.5.0: resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -6083,6 +6274,10 @@ packages: resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} engines: {node: '>= 0.4'} + es-abstract@1.24.1: + resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} + engines: {node: '>= 0.4'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -6206,6 +6401,27 @@ packages: eslint-import-resolver-webpack: optional: true + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + eslint-plugin-check-file@2.8.0: resolution: {integrity: sha512-FvvafMTam2WJYH9uj+FuMxQ1y+7jY3Z6P9T4j2214cH0FBxNzTcmeCiGTj1Lxp3mI6kbbgsXvmgewvf+llKYyw==} engines: {node: '>=18'} @@ -6226,6 +6442,16 @@ packages: '@typescript-eslint/parser': optional: true + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint-plugin-jest-dom@5.5.0: resolution: {integrity: sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6', yarn: '>=1'} @@ -6315,6 +6541,10 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + eslint@8.57.1: resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6478,6 +6708,15 @@ packages: picomatch: optional: true + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -6528,6 +6767,10 @@ packages: resolution: {integrity: sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==} engines: {node: '>= 0.4'} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -6707,23 +6950,20 @@ 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: 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 + deprecated: Glob versions prior to v9 are no longer supported 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==} @@ -6877,6 +7117,9 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + icu-minify@4.8.3: + resolution: {integrity: sha512-65Av7FLosNk7bPbmQx5z5XG2Y3T2GFppcjiXh4z1idHeVgQxlDpAmkGoYI0eFzAvrOnjpWTL5FmPDhsdfRMPEA==} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -6927,6 +7170,9 @@ packages: intl-messageformat@10.7.16: resolution: {integrity: sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==} + intl-messageformat@11.1.2: + resolution: {integrity: sha512-ucSrQmZGAxfiBHfBRXW/k7UC8MaGFlEj4Ry1tKiDcmgwQm1y3EDl40u+4VNHYomxJQMJi9NEI3riDRlth96jKg==} + ip-address@9.0.5: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} @@ -7034,6 +7280,10 @@ packages: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + is-node-process@1.2.0: resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} @@ -7129,6 +7379,10 @@ packages: resolution: {integrity: sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==} engines: {node: '>= 0.4'} + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + is-weakset@2.0.3: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} @@ -7790,6 +8044,10 @@ packages: resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} engines: {node: 20 || >=22} + minimatch@10.2.2: + resolution: {integrity: sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -7915,19 +8173,22 @@ packages: nodemailer: optional: true - next-intl@4.1.0: - resolution: {integrity: sha512-JNJRjc7sdnfUxhZmGcvzDszZ60tQKrygV/VLsgzXhnJDxQPn1cN2rVpc53adA1SvBJwPK2O6Sc6b4gYSILjCzw==} + next-intl-swc-plugin-extractor@4.8.3: + resolution: {integrity: sha512-YcaT+R9z69XkGhpDarVFWUprrCMbxgIQYPUaXoE6LGVnLjGdo8hu3gL6bramDVjNKViYY8a/pXPy7Bna0mXORg==} + + next-intl@4.8.3: + resolution: {integrity: sha512-PvdBDWg+Leh7BR7GJUQbCDVVaBRn37GwDBWc9sv0rVQOJDQ5JU1rVzx9EEGuOGYo0DHAl70++9LQ7HxTawdL7w==} peerDependencies: - next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 + next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - next@15.5.10: - resolution: {integrity: sha512-r0X65PNwyDDyOrWNKpQoZvOatw7BcsTPRKdwEqtc9cj3wv7mbBIk9tKed4klRaFXJdX0rugpuMTHslDrAU1bBg==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + next@16.1.6: + resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + engines: {node: '>=20.9.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -8052,6 +8313,10 @@ packages: resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} engines: {node: '>= 0.4'} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -8306,6 +8571,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -8338,6 +8607,9 @@ packages: engines: {node: '>=18'} hasBin: true + po-parser@2.1.1: + resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -8994,6 +9266,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} @@ -9032,8 +9309,8 @@ packages: resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - sharp@0.34.3: - resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -9191,6 +9468,10 @@ packages: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + stoppable@1.1.0: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} @@ -9429,6 +9710,10 @@ packages: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + tinypool@1.1.1: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -9505,6 +9790,12 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -9832,8 +10123,8 @@ packages: '@types/react': optional: true - use-intl@4.1.0: - resolution: {integrity: sha512-mQvDYFvoGn+bm/PWvlQOtluKCknsQ5a9F1Cj0hMfBjMBVTwnOqLPd6srhjvVdEQEQFVyHM1PfyifKqKYb11M9Q==} + use-intl@4.8.3: + resolution: {integrity: sha512-nLxlC/RH+le6g3amA508Itnn/00mE+J22ui21QhOWo5V9hCEC43+WtnRAITbJW0ztVZphev5X9gvOf2/Dk9PLA==} peerDependencies: react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 @@ -9989,7 +10280,6 @@ 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==} @@ -10027,6 +10317,10 @@ packages: resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} engines: {node: '>= 0.4'} + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + engines: {node: '>= 0.4'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -11506,6 +11800,39 @@ snapshots: - jest - supports-color + '@bigcommerce/eslint-config@2.11.0(@types/eslint@9.6.1)(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)': + dependencies: + '@bigcommerce/eslint-plugin': 1.4.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) + '@rushstack/eslint-patch': 1.11.0 + '@stylistic/eslint-plugin': 2.7.2(eslint@8.57.1)(typescript@5.8.3) + '@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) + '@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-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-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) + eslint-plugin-jsdoc: 50.6.9(eslint@8.57.1) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) + eslint-plugin-prettier: 5.4.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2) + eslint-plugin-react: 7.37.4(eslint@8.57.1) + eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) + eslint-plugin-switch-case: 1.1.2 + eslint-plugin-testing-library: 7.1.1(eslint@8.57.1)(typescript@5.8.3) + prettier: 3.6.2 + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - '@testing-library/dom' + - '@types/eslint' + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - jest + - supports-color + '@bigcommerce/eslint-plugin@1.4.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) @@ -11526,7 +11853,7 @@ snapshots: '@types/tough-cookie': 4.0.5 tough-cookie: 4.1.4 - '@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.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2)': + '@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)': dependencies: '@c15t/logger': 1.0.1 '@c15t/translations': 1.8.0 @@ -11542,7 +11869,7 @@ snapshots: base-x: 5.0.1 defu: 6.1.4 drizzle-orm: 0.44.7(@opentelemetry/api@1.9.0)(@upstash/redis@1.35.0)(kysely@0.27.6) - fumadb: 0.1.1(drizzle-orm@0.44.7(@opentelemetry/api@1.9.0)(@upstash/redis@1.35.0)(kysely@0.27.6))(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) + fumadb: 0.1.1(drizzle-orm@0.44.7(@opentelemetry/api@1.9.0)(@upstash/redis@1.35.0)(kysely@0.27.6))(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))) kysely: 0.27.6 neverthrow: 8.2.0 superjson: 2.2.2 @@ -11589,11 +11916,11 @@ 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@15.5.10(@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.11.31)(@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.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)': 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.11.31)(@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.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/translations': 1.8.0 - next: 15.5.10(@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.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) transitivePeerDependencies: @@ -11637,12 +11964,12 @@ 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.11.31)(@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.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)': 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.11.31)(@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.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) clsx: 2.1.1 react: 19.1.5 react-dom: 19.1.5(react@19.1.5) @@ -12195,6 +12522,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.8.1': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/wasi-threads@1.0.1': dependencies: tslib: 2.8.1 @@ -12364,8 +12696,15 @@ snapshots: eslint: 8.57.1 eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.1': {} + '@eslint-community/regexpp@4.12.2': {} + '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 @@ -12408,29 +12747,52 @@ snapshots: decimal.js: 10.5.0 tslib: 2.8.1 + '@formatjs/ecma402-abstract@3.1.1': + dependencies: + '@formatjs/fast-memoize': 3.1.0 + '@formatjs/intl-localematcher': 0.8.1 + decimal.js: 10.6.0 + tslib: 2.8.1 + '@formatjs/fast-memoize@2.2.7': dependencies: tslib: 2.8.1 + '@formatjs/fast-memoize@3.1.0': + dependencies: + tslib: 2.8.1 + '@formatjs/icu-messageformat-parser@2.11.2': dependencies: '@formatjs/ecma402-abstract': 2.3.4 '@formatjs/icu-skeleton-parser': 1.8.14 tslib: 2.8.1 + '@formatjs/icu-messageformat-parser@3.5.1': + dependencies: + '@formatjs/ecma402-abstract': 3.1.1 + '@formatjs/icu-skeleton-parser': 2.1.1 + tslib: 2.8.1 + '@formatjs/icu-skeleton-parser@1.8.14': dependencies: '@formatjs/ecma402-abstract': 2.3.4 tslib: 2.8.1 - '@formatjs/intl-localematcher@0.5.10': + '@formatjs/icu-skeleton-parser@2.1.1': dependencies: + '@formatjs/ecma402-abstract': 3.1.1 tslib: 2.8.1 '@formatjs/intl-localematcher@0.6.1': dependencies: tslib: 2.8.1 + '@formatjs/intl-localematcher@0.8.1': + dependencies: + '@formatjs/fast-memoize': 3.1.0 + tslib: 2.8.1 + '@gql.tada/cli-utils@1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.11.0)(typescript@5.8.3))(graphql@16.11.0)(typescript@5.8.3)': dependencies: '@0no-co/graphqlsp': 1.12.16(graphql@16.11.0)(typescript@5.8.3) @@ -12479,14 +12841,17 @@ snapshots: dependencies: react: 19.1.5 + '@img/colour@1.0.0': + optional: true + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 optional: true - '@img/sharp-darwin-arm64@0.34.3': + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.0 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true '@img/sharp-darwin-x64@0.33.5': @@ -12494,60 +12859,63 @@ snapshots: '@img/sharp-libvips-darwin-x64': 1.0.4 optional: true - '@img/sharp-darwin-x64@0.34.3': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.0 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true '@img/sharp-libvips-darwin-arm64@1.0.4': optional: true - '@img/sharp-libvips-darwin-arm64@1.2.0': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true '@img/sharp-libvips-darwin-x64@1.0.4': optional: true - '@img/sharp-libvips-darwin-x64@1.2.0': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true '@img/sharp-libvips-linux-arm64@1.0.4': optional: true - '@img/sharp-libvips-linux-arm64@1.2.0': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true '@img/sharp-libvips-linux-arm@1.0.5': optional: true - '@img/sharp-libvips-linux-arm@1.2.0': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.0': + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true '@img/sharp-libvips-linux-s390x@1.0.4': optional: true - '@img/sharp-libvips-linux-s390x@1.2.0': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true '@img/sharp-libvips-linux-x64@1.0.4': optional: true - '@img/sharp-libvips-linux-x64@1.2.0': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true '@img/sharp-libvips-linuxmusl-arm64@1.0.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true '@img/sharp-libvips-linuxmusl-x64@1.0.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.0': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true '@img/sharp-linux-arm64@0.33.5': @@ -12555,9 +12923,9 @@ snapshots: '@img/sharp-libvips-linux-arm64': 1.0.4 optional: true - '@img/sharp-linux-arm64@0.34.3': + '@img/sharp-linux-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.0 + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true '@img/sharp-linux-arm@0.33.5': @@ -12565,14 +12933,19 @@ snapshots: '@img/sharp-libvips-linux-arm': 1.0.5 optional: true - '@img/sharp-linux-arm@0.34.3': + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.0 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-ppc64@0.34.3': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.0 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true '@img/sharp-linux-s390x@0.33.5': @@ -12580,9 +12953,9 @@ snapshots: '@img/sharp-libvips-linux-s390x': 1.0.4 optional: true - '@img/sharp-linux-s390x@0.34.3': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.0 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true '@img/sharp-linux-x64@0.33.5': @@ -12590,9 +12963,9 @@ snapshots: '@img/sharp-libvips-linux-x64': 1.0.4 optional: true - '@img/sharp-linux-x64@0.34.3': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.0 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true '@img/sharp-linuxmusl-arm64@0.33.5': @@ -12600,9 +12973,9 @@ snapshots: '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 optional: true - '@img/sharp-linuxmusl-arm64@0.34.3': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true '@img/sharp-linuxmusl-x64@0.33.5': @@ -12610,34 +12983,34 @@ snapshots: '@img/sharp-libvips-linuxmusl-x64': 1.0.4 optional: true - '@img/sharp-linuxmusl-x64@0.34.3': + '@img/sharp-linuxmusl-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true '@img/sharp-wasm32@0.33.5': dependencies: - '@emnapi/runtime': 1.4.5 + '@emnapi/runtime': 1.8.1 optional: true - '@img/sharp-wasm32@0.34.3': + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.4.5 + '@emnapi/runtime': 1.8.1 optional: true - '@img/sharp-win32-arm64@0.34.3': + '@img/sharp-win32-arm64@0.34.5': optional: true '@img/sharp-win32-ia32@0.33.5': optional: true - '@img/sharp-win32-ia32@0.34.3': + '@img/sharp-win32-ia32@0.34.5': optional: true '@img/sharp-win32-x64@0.33.5': optional: true - '@img/sharp-win32-x64@0.34.3': + '@img/sharp-win32-x64@0.34.5': optional: true '@inquirer/checkbox@4.1.8(@types/node@22.15.30)': @@ -12825,22 +13198,58 @@ snapshots: - supports-color - ts-node - '@jest/create-cache-key-function@29.7.0': - dependencies: - '@jest/types': 29.6.3 - - '@jest/environment@29.7.0': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3))': dependencies: - '@jest/fake-timers': 29.7.0 + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@types/node': 22.15.30 - jest-mock: 29.7.0 - - '@jest/expect-utils@29.7.0': - dependencies: - jest-get-type: 29.6.3 - - '@jest/expect@29.7.0': + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 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)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + optional: true + + '@jest/create-cache-key-function@29.7.0': + dependencies: + '@jest/types': 29.6.3 + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.15.30 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0': dependencies: expect: 29.7.0 jest-snapshot: 29.7.0 @@ -13037,45 +13446,45 @@ snapshots: '@tybys/wasm-util': 0.9.0 optional: true - '@next/bundle-analyzer@15.5.10': + '@next/bundle-analyzer@16.1.6': dependencies: webpack-bundle-analyzer: 4.10.1 transitivePeerDependencies: - bufferutil - utf-8-validate - '@next/env@15.5.10': {} + '@next/env@16.1.6': {} - '@next/eslint-plugin-next@15.3.3': + '@next/eslint-plugin-next@15.5.10': dependencies: fast-glob: 3.3.1 - '@next/eslint-plugin-next@15.5.10': + '@next/eslint-plugin-next@15.5.12': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.5.7': + '@next/swc-darwin-arm64@16.1.6': optional: true - '@next/swc-darwin-x64@15.5.7': + '@next/swc-darwin-x64@16.1.6': optional: true - '@next/swc-linux-arm64-gnu@15.5.7': + '@next/swc-linux-arm64-gnu@16.1.6': optional: true - '@next/swc-linux-arm64-musl@15.5.7': + '@next/swc-linux-arm64-musl@16.1.6': optional: true - '@next/swc-linux-x64-gnu@15.5.7': + '@next/swc-linux-x64-gnu@16.1.6': optional: true - '@next/swc-linux-x64-musl@15.5.7': + '@next/swc-linux-x64-musl@16.1.6': optional: true - '@next/swc-win32-arm64-msvc@15.5.7': + '@next/swc-win32-arm64-msvc@16.1.6': optional: true - '@next/swc-win32-x64-msvc@15.5.7': + '@next/swc-win32-x64-msvc@16.1.6': optional: true '@noble/ciphers@1.3.0': {} @@ -13718,7 +14127,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 @@ -15350,33 +15759,63 @@ snapshots: '@swc/core-darwin-arm64@1.11.31': optional: true + '@swc/core-darwin-arm64@1.15.18': + optional: true + '@swc/core-darwin-x64@1.11.31': optional: true + '@swc/core-darwin-x64@1.15.18': + optional: true + '@swc/core-linux-arm-gnueabihf@1.11.31': optional: true + '@swc/core-linux-arm-gnueabihf@1.15.18': + optional: true + '@swc/core-linux-arm64-gnu@1.11.31': optional: true + '@swc/core-linux-arm64-gnu@1.15.18': + optional: true + '@swc/core-linux-arm64-musl@1.11.31': optional: true + '@swc/core-linux-arm64-musl@1.15.18': + optional: true + '@swc/core-linux-x64-gnu@1.11.31': optional: true + '@swc/core-linux-x64-gnu@1.15.18': + optional: true + '@swc/core-linux-x64-musl@1.11.31': optional: true + '@swc/core-linux-x64-musl@1.15.18': + optional: true + '@swc/core-win32-arm64-msvc@1.11.31': optional: true + '@swc/core-win32-arm64-msvc@1.15.18': + optional: true + '@swc/core-win32-ia32-msvc@1.11.31': optional: true + '@swc/core-win32-ia32-msvc@1.15.18': + optional: true + '@swc/core-win32-x64-msvc@1.11.31': optional: true + '@swc/core-win32-x64-msvc@1.15.18': + optional: true + '@swc/core@1.11.31': dependencies: '@swc/counter': 0.1.3 @@ -15393,6 +15832,22 @@ snapshots: '@swc/core-win32-ia32-msvc': 1.11.31 '@swc/core-win32-x64-msvc': 1.11.31 + '@swc/core@1.15.18': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.25 + optionalDependencies: + '@swc/core-darwin-arm64': 1.15.18 + '@swc/core-darwin-x64': 1.15.18 + '@swc/core-linux-arm-gnueabihf': 1.15.18 + '@swc/core-linux-arm64-gnu': 1.15.18 + '@swc/core-linux-arm64-musl': 1.15.18 + '@swc/core-linux-x64-gnu': 1.15.18 + '@swc/core-linux-x64-musl': 1.15.18 + '@swc/core-win32-arm64-msvc': 1.15.18 + '@swc/core-win32-ia32-msvc': 1.15.18 + '@swc/core-win32-x64-msvc': 1.15.18 + '@swc/counter@0.1.3': {} '@swc/helpers@0.5.15': @@ -15410,6 +15865,10 @@ snapshots: dependencies: '@swc/counter': 0.1.3 + '@swc/types@0.1.25': + dependencies: + '@swc/counter': 0.1.3 + '@szmarczak/http-timer@4.0.6': dependencies: defer-to-connect: 2.0.1 @@ -15419,17 +15878,17 @@ snapshots: typescript: 5.8.3 zod: 3.25.51 - '@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))': + '@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))': dependencies: - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)) - '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))': + '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)) '@tanstack/virtual-core@3.13.9': {} @@ -15641,6 +16100,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.56.1(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/type-utils': 8.56.1(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.56.1 + eslint: 8.57.1 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.28.0 @@ -15653,11 +16128,41 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.56.1 + debug: 4.4.3 + eslint: 8.57.1 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.56.1(typescript@5.8.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.8.3) + '@typescript-eslint/types': 8.56.1 + debug: 4.4.3 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.28.0': dependencies: '@typescript-eslint/types': 8.28.0 '@typescript-eslint/visitor-keys': 8.28.0 + '@typescript-eslint/scope-manager@8.56.1': + dependencies: + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 + + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.8.3)': + dependencies: + typescript: 5.8.3 + '@typescript-eslint/type-utils@8.28.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@typescript-eslint/typescript-estree': 8.28.0(typescript@5.8.3) @@ -15669,8 +16174,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.56.1(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.3) + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@5.8.3) + debug: 4.4.3 + eslint: 8.57.1 + ts-api-utils: 2.4.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.28.0': {} + '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/typescript-estree@8.28.0(typescript@5.8.3)': dependencies: '@typescript-eslint/types': 8.28.0 @@ -15679,12 +16198,27 @@ snapshots: fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.2 + semver: 7.7.4 ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.56.1(typescript@5.8.3)': + dependencies: + '@typescript-eslint/project-service': 8.56.1(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.8.3) + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 + debug: 4.4.3 + minimatch: 10.2.2 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.28.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@eslint-community/eslint-utils': 4.5.1(eslint@8.57.1) @@ -15696,11 +16230,27 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.56.1(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.3) + eslint: 8.57.1 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.28.0': dependencies: '@typescript-eslint/types': 8.28.0 eslint-visitor-keys: 4.2.0 + '@typescript-eslint/visitor-keys@8.56.1': + dependencies: + '@typescript-eslint/types': 8.56.1 + eslint-visitor-keys: 5.0.1 + '@ungap/structured-clone@1.2.0': {} '@unlighthouse/cli@0.16.3(encoding@0.1.13)(magicast@0.3.5)(puppeteer@24.10.0(typescript@5.8.3))(rollup@4.44.2)(typescript@5.8.3)': @@ -15897,9 +16447,9 @@ snapshots: dependencies: uncrypto: 0.1.3 - '@vercel/analytics@1.5.0(next@15.5.10(@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.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))': optionalDependencies: - next: 15.5.10(@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.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) @@ -15925,9 +16475,9 @@ 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@15.5.10(@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.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))': optionalDependencies: - next: 15.5.10(@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.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) @@ -16189,6 +16739,17 @@ snapshots: get-intrinsic: 1.3.0 is-string: 1.1.1 + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + array-union@2.1.0: {} array.prototype.findlast@1.2.5: @@ -16349,6 +16910,8 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + bare-events@2.5.4: optional: true @@ -16378,6 +16941,8 @@ snapshots: base64-js@1.5.1: {} + baseline-browser-mapping@2.10.0: {} + basic-ftp@5.0.5: {} better-opn@3.0.2: @@ -16421,6 +16986,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.3: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -16478,9 +17047,9 @@ 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.11.31)(@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.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): 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.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(ws@8.18.2) + '@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) @@ -16841,6 +17410,22 @@ snapshots: - supports-color - ts-node + create-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)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 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)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + optional: true + create-require@1.1.1: optional: true @@ -16964,6 +17549,8 @@ snapshots: decimal.js@10.5.0: {} + decimal.js@10.6.0: {} + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -17246,6 +17833,63 @@ snapshots: unbox-primitive: 1.1.0 which-typed-array: 1.1.18 + es-abstract@1.24.1: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.20 + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -17371,12 +18015,12 @@ snapshots: dependencies: '@next/eslint-plugin-next': 15.5.10 '@rushstack/eslint-patch': 1.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) - '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/parser': 8.56.1(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.32.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(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) @@ -17418,7 +18062,22 @@ snapshots: 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-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.32.0(@typescript-eslint/parser@8.56.1(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.32.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(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: @@ -17429,6 +18088,17 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.56.1(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.32.0(@typescript-eslint/parser@8.56.1(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.56.1(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.32.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + eslint-plugin-check-file@2.8.0(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -17450,7 +18120,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-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-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 @@ -17468,6 +18138,35 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(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.9 + 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.1(@typescript-eslint/parser@8.56.1(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.32.0(@typescript-eslint/parser@8.56.1(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.56.1(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 @@ -17489,6 +18188,17 @@ snapshots: - supports-color - typescript + 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): + dependencies: + '@typescript-eslint/utils': 8.28.0(eslint@8.57.1)(typescript@5.8.3) + eslint: 8.57.1 + optionalDependencies: + '@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) + 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)) + transitivePeerDependencies: + - supports-color + - typescript + eslint-plugin-jsdoc@50.6.9(eslint@8.57.1): dependencies: '@es-joy/jsdoccomment': 0.49.0 @@ -17594,6 +18304,8 @@ snapshots: eslint-visitor-keys@4.2.0: {} + eslint-visitor-keys@5.0.1: {} + eslint@8.57.1: dependencies: '@eslint-community/eslint-utils': 4.5.1(eslint@8.57.1) @@ -17851,6 +18563,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + fflate@0.8.2: {} figures@6.1.0: @@ -17906,6 +18622,10 @@ snapshots: dependencies: is-callable: 1.2.7 + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.6 @@ -17974,18 +18694,18 @@ snapshots: fsevents@2.3.3: optional: true - fumadb@0.1.1(drizzle-orm@0.44.7(@opentelemetry/api@1.9.0)(@upstash/redis@1.35.0)(kysely@0.27.6))(typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))): + fumadb@0.1.1(drizzle-orm@0.44.7(@opentelemetry/api@1.9.0)(@upstash/redis@1.35.0)(kysely@0.27.6))(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))): dependencies: '@clack/prompts': 0.11.0 '@paralleldrive/cuid2': 2.2.2 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.11.31)(@types/node@22.15.30)(typescript@5.8.3))) - semver: 7.7.2 + 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.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) - typeorm: 0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) + 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)) function-bind@1.1.2: {} @@ -18312,6 +19032,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + icu-minify@4.8.3: + dependencies: + '@formatjs/icu-messageformat-parser': 3.5.1 + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -18368,6 +19092,13 @@ snapshots: '@formatjs/icu-messageformat-parser': 2.11.2 tslib: 2.8.1 + intl-messageformat@11.1.2: + dependencies: + '@formatjs/ecma402-abstract': 3.1.1 + '@formatjs/fast-memoize': 3.1.0 + '@formatjs/icu-messageformat-parser': 3.5.1 + tslib: 2.8.1 + ip-address@9.0.5: dependencies: jsbn: 1.1.0 @@ -18464,6 +19195,8 @@ snapshots: is-map@2.0.3: {} + is-negative-zero@2.0.3: {} + is-node-process@1.2.0: {} is-number-object@1.1.1: @@ -18541,6 +19274,10 @@ snapshots: dependencies: call-bound: 1.0.4 + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + is-weakset@2.0.3: dependencies: call-bind: 1.0.8 @@ -18593,7 +19330,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 @@ -18694,6 +19431,26 @@ snapshots: - supports-color - ts-node + jest-cli@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)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-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)) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 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)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + optional: true + jest-config@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: '@babel/core': 7.27.4 @@ -18725,6 +19482,38 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@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)): + dependencies: + '@babel/core': 7.27.4 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.27.4) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.15.30 + ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + optional: true + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -18900,7 +19689,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 @@ -18952,6 +19741,19 @@ snapshots: - supports-color - ts-node + 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)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)) + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 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)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + optional: true + jiti@1.21.7: {} jiti@2.4.2: {} @@ -19060,10 +19862,10 @@ snapshots: knitwork@1.2.0: {} - 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.11.31)(@types/node@22.15.30)(typescript@5.8.3))): + 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))): dependencies: kysely: 0.28.8 - typeorm: 0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) + 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)) kysely@0.27.6: {} @@ -19352,7 +20154,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.4 make-error@1.3.6: optional: true @@ -19428,6 +20230,10 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 + minimatch@10.2.2: + dependencies: + brace-expansion: 5.0.3 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -19531,43 +20337,53 @@ snapshots: optionalDependencies: '@rollup/rollup-linux-x64-gnu': 4.44.2 - next-auth@5.0.0-beta.30(next@15.5.10(@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.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): dependencies: '@auth/core': 0.41.0 - next: 15.5.10(@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.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-intl@4.1.0(next@15.5.10(@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-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): dependencies: - '@formatjs/intl-localematcher': 0.5.10 + '@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: 15.5.10(@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.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-intl-swc-plugin-extractor: 4.8.3 + po-parser: 2.1.1 react: 19.1.5 - use-intl: 4.1.0(react@19.1.5) + use-intl: 4.8.3(react@19.1.5) optionalDependencies: typescript: 5.8.3 + transitivePeerDependencies: + - '@swc/helpers' - next@15.5.10(@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.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): dependencies: - '@next/env': 15.5.10 + '@next/env': 16.1.6 '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.10.0 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) optionalDependencies: - '@next/swc-darwin-arm64': 15.5.7 - '@next/swc-darwin-x64': 15.5.7 - '@next/swc-linux-arm64-gnu': 15.5.7 - '@next/swc-linux-arm64-musl': 15.5.7 - '@next/swc-linux-x64-gnu': 15.5.7 - '@next/swc-linux-x64-musl': 15.5.7 - '@next/swc-win32-arm64-msvc': 15.5.7 - '@next/swc-win32-x64-msvc': 15.5.7 + '@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 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.52.0 - sharp: 0.34.3 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -19615,12 +20431,12 @@ snapshots: dependencies: boolbase: 1.0.0 - nuqs@2.4.3(next@15.5.10(@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.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): dependencies: mitt: 3.0.1 react: 19.1.5 optionalDependencies: - next: 15.5.10(@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.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) nwsapi@2.2.20: optional: true @@ -19650,6 +20466,8 @@ snapshots: object-inspect@1.13.3: {} + object-inspect@1.13.4: {} + object-keys@1.1.1: {} object-treeify@1.1.33: {} @@ -19905,6 +20723,8 @@ snapshots: picomatch@4.0.2: {} + picomatch@4.0.3: {} + pify@2.3.0: {} pify@4.0.1: {} @@ -19935,6 +20755,8 @@ snapshots: optionalDependencies: fsevents: 2.3.2 + po-parser@2.1.1: {} + possible-typed-array-names@1.0.0: {} postcss-attribute-case-insensitive@7.0.1(postcss@8.5.6): @@ -20050,13 +20872,13 @@ snapshots: '@csstools/utilities': 2.0.0(postcss@8.5.6) postcss: 8.5.6 - postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): + postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: lilconfig: 3.1.3 yaml: 2.6.0 optionalDependencies: postcss: 8.5.6 - ts-node: 10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3) + ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3) postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.6)(yaml@2.8.1): dependencies: @@ -20662,6 +21484,8 @@ snapshots: semver@7.7.2: {} + semver@7.7.4: {} + send@1.2.0: dependencies: debug: 4.4.3 @@ -20725,7 +21549,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 @@ -20747,34 +21571,36 @@ snapshots: '@img/sharp-win32-ia32': 0.33.5 '@img/sharp-win32-x64': 0.33.5 - sharp@0.34.3: + sharp@0.34.5: dependencies: - color: 4.2.3 + '@img/colour': 1.0.0 detect-libc: 2.1.2 - semver: 7.7.2 + semver: 7.7.4 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.3 - '@img/sharp-darwin-x64': 0.34.3 - '@img/sharp-libvips-darwin-arm64': 1.2.0 - '@img/sharp-libvips-darwin-x64': 1.2.0 - '@img/sharp-libvips-linux-arm': 1.2.0 - '@img/sharp-libvips-linux-arm64': 1.2.0 - '@img/sharp-libvips-linux-ppc64': 1.2.0 - '@img/sharp-libvips-linux-s390x': 1.2.0 - '@img/sharp-libvips-linux-x64': 1.2.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - '@img/sharp-linux-arm': 0.34.3 - '@img/sharp-linux-arm64': 0.34.3 - '@img/sharp-linux-ppc64': 0.34.3 - '@img/sharp-linux-s390x': 0.34.3 - '@img/sharp-linux-x64': 0.34.3 - '@img/sharp-linuxmusl-arm64': 0.34.3 - '@img/sharp-linuxmusl-x64': 0.34.3 - '@img/sharp-wasm32': 0.34.3 - '@img/sharp-win32-arm64': 0.34.3 - '@img/sharp-win32-ia32': 0.34.3 - '@img/sharp-win32-x64': 0.34.3 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -20930,6 +21756,11 @@ snapshots: stdin-discarder@0.2.2: {} + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + stoppable@1.1.0: {} streamx@2.22.1: @@ -21118,15 +21949,15 @@ snapshots: tagged-tag@1.0.0: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))): + tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3))): dependencies: - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)) - tailwindcss-radix@3.0.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))): + tailwindcss-radix@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))): dependencies: - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)) - tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): + tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -21145,7 +21976,7 @@ snapshots: postcss: 8.5.6 postcss-import: 15.1.0(postcss@8.5.6) postcss-js: 4.0.1(postcss@8.5.6) - postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) + postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3)) postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 resolve: 1.22.10 @@ -21230,6 +22061,11 @@ snapshots: fdir: 6.4.6(picomatch@4.0.2) picomatch: 4.0.2 + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + tinypool@1.1.1: {} tinyrainbow@2.0.0: {} @@ -21300,6 +22136,10 @@ snapshots: dependencies: typescript: 5.8.3 + ts-api-utils@2.4.0(typescript@5.8.3): + dependencies: + typescript: 5.8.3 + ts-interface-checker@0.1.13: {} ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3): @@ -21323,6 +22163,27 @@ snapshots: '@swc/core': 1.11.31 optional: true + ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.15.30 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.8.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + '@swc/core': 1.15.18 + optional: true + ts-tqdm@0.8.6: {} tsconfig-paths@3.15.0: @@ -21365,6 +22226,35 @@ snapshots: - tsx - yaml + tsup@8.5.0(@swc/core@1.15.18)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1): + dependencies: + bundle-require: 5.1.0(esbuild@0.25.6) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.1 + esbuild: 0.25.6 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.6)(yaml@2.8.1) + resolve-from: 5.0.0 + rollup: 4.44.2 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.14 + tree-kill: 1.2.2 + optionalDependencies: + '@swc/core': 1.15.18 + postcss: 8.5.6 + typescript: 5.8.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + tsutils@3.21.0(typescript@5.8.3): dependencies: tslib: 1.14.1 @@ -21460,7 +22350,7 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typeorm@0.3.27(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): + 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)): dependencies: '@sqltools/formatter': 1.2.5 ansis: 3.17.0 @@ -21478,7 +22368,7 @@ snapshots: uuid: 11.1.0 yargs: 17.7.2 optionalDependencies: - ts-node: 10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3) + ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@22.15.30)(typescript@5.8.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -21641,11 +22531,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.7 - use-intl@4.1.0(react@19.1.5): + use-intl@4.8.3(react@19.1.5): dependencies: - '@formatjs/fast-memoize': 2.2.7 + '@formatjs/fast-memoize': 3.1.0 '@schummar/icu-type-parser': 1.21.5 - intl-messageformat: 10.7.16 + icu-minify: 4.8.3 + intl-messageformat: 11.1.2 react: 19.1.5 use-sidecar@1.1.3(@types/react@19.2.7)(react@19.1.5): @@ -21873,6 +22764,16 @@ snapshots: gopd: 1.2.0 has-tostringtag: 1.0.2 + which-typed-array@1.1.20: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + which@2.0.2: dependencies: isexe: 2.0.0 From d1728c1ebf92ff0f147c2257c19b04777dbbef7e Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Wed, 25 Feb 2026 10:53:25 -0600 Subject: [PATCH 03/24] refactor(core): replace unstable_expireTag with revalidateTag --- .../(default)/account/addresses/_actions/create-address.ts | 4 ++-- .../(default)/account/addresses/_actions/delete-address.ts | 4 ++-- .../(default)/account/addresses/_actions/update-address.ts | 4 ++-- .../(default)/account/settings/_actions/update-customer.ts | 4 ++-- .../settings/_actions/update-newsletter-subscription.ts | 4 ++-- .../wishlists/_actions/change-wishlist-visibility.ts | 2 +- .../(default)/account/wishlists/_actions/delete-wishlist.ts | 2 +- .../(default)/account/wishlists/_actions/new-wishlist.ts | 2 +- .../account/wishlists/_actions/remove-wishlist-item.ts | 2 +- .../(default)/account/wishlists/_actions/rename-wishlist.ts | 2 +- .../[locale]/(default)/cart/_actions/add-shipping-cost.ts | 2 +- .../[locale]/(default)/cart/_actions/add-shipping-info.ts | 4 ++-- .../[locale]/(default)/cart/_actions/apply-coupon-code.ts | 2 +- .../(default)/cart/_actions/apply-gift-certificate.ts | 2 +- .../[locale]/(default)/cart/_actions/remove-coupon-code.ts | 2 +- .../(default)/cart/_actions/remove-gift-certificate.ts | 2 +- core/app/[locale]/(default)/cart/_actions/remove-item.ts | 4 ++-- .../(default)/product/[slug]/_actions/wishlist-action.ts | 2 +- core/components/header/_actions/switch-currency.ts | 2 +- core/lib/cart/index.ts | 6 +++--- .../soul/sections/product-detail/actions/revalidate-cart.ts | 2 +- 21 files changed, 30 insertions(+), 30 deletions(-) diff --git a/core/app/[locale]/(default)/account/addresses/_actions/create-address.ts b/core/app/[locale]/(default)/account/addresses/_actions/create-address.ts index e6f67f0cea..6d7df51ab1 100644 --- a/core/app/[locale]/(default)/account/addresses/_actions/create-address.ts +++ b/core/app/[locale]/(default)/account/addresses/_actions/create-address.ts @@ -1,6 +1,6 @@ import { BigCommerceAPIError, BigCommerceGQLError } from '@bigcommerce/catalyst-client'; import { parseWithZod } from '@conform-to/zod'; -import { unstable_expireTag as expireTag } from 'next/cache'; +import { revalidateTag } from 'next/cache'; import { getTranslations } from 'next-intl/server'; import { z } from 'zod'; @@ -234,7 +234,7 @@ export async function createAddress( }; } - expireTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); return { addresses: [ diff --git a/core/app/[locale]/(default)/account/addresses/_actions/delete-address.ts b/core/app/[locale]/(default)/account/addresses/_actions/delete-address.ts index 4760fb1668..f1b1a1314e 100644 --- a/core/app/[locale]/(default)/account/addresses/_actions/delete-address.ts +++ b/core/app/[locale]/(default)/account/addresses/_actions/delete-address.ts @@ -1,6 +1,6 @@ import { BigCommerceGQLError } from '@bigcommerce/catalyst-client'; import { parseWithZod } from '@conform-to/zod'; -import { unstable_expireTag as expireTag } from 'next/cache'; +import { revalidateTag } from 'next/cache'; import { getTranslations } from 'next-intl/server'; import { z } from 'zod'; @@ -78,7 +78,7 @@ export async function deleteAddress(prevState: Awaited, formData: FormDat }; } - expireTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); return { addresses: prevState.addresses.filter( diff --git a/core/app/[locale]/(default)/account/addresses/_actions/update-address.ts b/core/app/[locale]/(default)/account/addresses/_actions/update-address.ts index 8547f4d7b1..0435290bae 100644 --- a/core/app/[locale]/(default)/account/addresses/_actions/update-address.ts +++ b/core/app/[locale]/(default)/account/addresses/_actions/update-address.ts @@ -1,6 +1,6 @@ import { BigCommerceGQLError } from '@bigcommerce/catalyst-client'; import { parseWithZod } from '@conform-to/zod'; -import { unstable_expireTag as expireTag } from 'next/cache'; +import { revalidateTag } from 'next/cache'; import { getTranslations } from 'next-intl/server'; import { z } from 'zod'; @@ -247,7 +247,7 @@ export async function updateAddress( }; } - expireTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); return { addresses: prevState.addresses.map((address) => diff --git a/core/app/[locale]/(default)/account/settings/_actions/update-customer.ts b/core/app/[locale]/(default)/account/settings/_actions/update-customer.ts index 8d678d562c..90f673bd55 100644 --- a/core/app/[locale]/(default)/account/settings/_actions/update-customer.ts +++ b/core/app/[locale]/(default)/account/settings/_actions/update-customer.ts @@ -2,7 +2,7 @@ import { BigCommerceGQLError } from '@bigcommerce/catalyst-client'; import { parseWithZod } from '@conform-to/zod'; -import { unstable_expireTag } from 'next/cache'; +import { revalidateTag } from 'next/cache'; import { getTranslations } from 'next-intl/server'; import { updateAccountSchema } from '@/vibes/soul/sections/account-settings/schema'; @@ -75,7 +75,7 @@ export const updateCustomer: UpdateAccountAction = async (prevState, formData) = }; } - unstable_expireTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); return { account: submission.value, diff --git a/core/app/[locale]/(default)/account/settings/_actions/update-newsletter-subscription.ts b/core/app/[locale]/(default)/account/settings/_actions/update-newsletter-subscription.ts index b984b53601..2ecf52d63c 100644 --- a/core/app/[locale]/(default)/account/settings/_actions/update-newsletter-subscription.ts +++ b/core/app/[locale]/(default)/account/settings/_actions/update-newsletter-subscription.ts @@ -3,7 +3,7 @@ import { BigCommerceGQLError } from '@bigcommerce/catalyst-client'; import { SubmissionResult } from '@conform-to/react'; import { parseWithZod } from '@conform-to/zod'; -import { unstable_expireTag } from 'next/cache'; +import { revalidateTag } from 'next/cache'; import { getTranslations } from 'next-intl/server'; import { z } from 'zod'; @@ -120,7 +120,7 @@ export const updateNewsletterSubscription = async ( }; } - unstable_expireTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); return { lastResult: submission.reply(), diff --git a/core/app/[locale]/(default)/account/wishlists/_actions/change-wishlist-visibility.ts b/core/app/[locale]/(default)/account/wishlists/_actions/change-wishlist-visibility.ts index 46ff104696..3f8f8547da 100644 --- a/core/app/[locale]/(default)/account/wishlists/_actions/change-wishlist-visibility.ts +++ b/core/app/[locale]/(default)/account/wishlists/_actions/change-wishlist-visibility.ts @@ -63,7 +63,7 @@ export async function toggleWishlistVisibility( }; } - revalidateTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); return { lastResult: submission.reply(), diff --git a/core/app/[locale]/(default)/account/wishlists/_actions/delete-wishlist.ts b/core/app/[locale]/(default)/account/wishlists/_actions/delete-wishlist.ts index b63ec01a89..8a5498671e 100644 --- a/core/app/[locale]/(default)/account/wishlists/_actions/delete-wishlist.ts +++ b/core/app/[locale]/(default)/account/wishlists/_actions/delete-wishlist.ts @@ -60,7 +60,7 @@ export async function deleteWishlist( }; } - revalidateTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); // Server toast has to be used here since the item is being deleted. When revalidateTag is called, // the wishlist items will update, and the element node containing the useEffect will be removed. diff --git a/core/app/[locale]/(default)/account/wishlists/_actions/new-wishlist.ts b/core/app/[locale]/(default)/account/wishlists/_actions/new-wishlist.ts index 1df54efdc6..dbf86eb612 100644 --- a/core/app/[locale]/(default)/account/wishlists/_actions/new-wishlist.ts +++ b/core/app/[locale]/(default)/account/wishlists/_actions/new-wishlist.ts @@ -58,7 +58,7 @@ export async function newWishlist(prevState: Awaited, formData: FormData) }; } - revalidateTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); return { lastResult: submission.reply(), diff --git a/core/app/[locale]/(default)/account/wishlists/_actions/remove-wishlist-item.ts b/core/app/[locale]/(default)/account/wishlists/_actions/remove-wishlist-item.ts index 5bee617081..39fcad84da 100644 --- a/core/app/[locale]/(default)/account/wishlists/_actions/remove-wishlist-item.ts +++ b/core/app/[locale]/(default)/account/wishlists/_actions/remove-wishlist-item.ts @@ -63,7 +63,7 @@ export async function removeWishlistItem( }; } - revalidateTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); // Server toast has to be used here since the item is being deleted. When revalidateTag is called, // the wishlist items will update, and the element node containing the useEffect will be removed. diff --git a/core/app/[locale]/(default)/account/wishlists/_actions/rename-wishlist.ts b/core/app/[locale]/(default)/account/wishlists/_actions/rename-wishlist.ts index 0446c4e6b0..33d7c45ecd 100644 --- a/core/app/[locale]/(default)/account/wishlists/_actions/rename-wishlist.ts +++ b/core/app/[locale]/(default)/account/wishlists/_actions/rename-wishlist.ts @@ -60,7 +60,7 @@ export async function renameWishlist( }; } - revalidateTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); return { lastResult: submission.reply(), diff --git a/core/app/[locale]/(default)/cart/_actions/add-shipping-cost.ts b/core/app/[locale]/(default)/cart/_actions/add-shipping-cost.ts index cd6566f838..5550033fb9 100644 --- a/core/app/[locale]/(default)/cart/_actions/add-shipping-cost.ts +++ b/core/app/[locale]/(default)/cart/_actions/add-shipping-cost.ts @@ -49,7 +49,7 @@ export const addShippingCost = async ({ const result = response.data.checkout.selectCheckoutShippingOption?.checkout; - revalidateTag(TAGS.checkout); + revalidateTag(TAGS.checkout, { expire: 0 }); return result; }; diff --git a/core/app/[locale]/(default)/cart/_actions/add-shipping-info.ts b/core/app/[locale]/(default)/cart/_actions/add-shipping-info.ts index 87200afc1f..fd29033f17 100644 --- a/core/app/[locale]/(default)/cart/_actions/add-shipping-info.ts +++ b/core/app/[locale]/(default)/cart/_actions/add-shipping-info.ts @@ -68,7 +68,7 @@ export const addCheckoutShippingConsignments = async ({ fetchOptions: { cache: 'no-store' }, }); - revalidateTag(TAGS.checkout); + revalidateTag(TAGS.checkout, { expire: 0 }); return response.data.checkout.addCheckoutShippingConsignments?.checkout; }; @@ -135,7 +135,7 @@ export const updateCheckoutShippingConsignment = async ({ fetchOptions: { cache: 'no-store' }, }); - revalidateTag(TAGS.checkout); + revalidateTag(TAGS.checkout, { expire: 0 }); return response.data.checkout.updateCheckoutShippingConsignment?.checkout; }; diff --git a/core/app/[locale]/(default)/cart/_actions/apply-coupon-code.ts b/core/app/[locale]/(default)/cart/_actions/apply-coupon-code.ts index 604e9e3d5c..ed0347eb3c 100644 --- a/core/app/[locale]/(default)/cart/_actions/apply-coupon-code.ts +++ b/core/app/[locale]/(default)/cart/_actions/apply-coupon-code.ts @@ -45,7 +45,7 @@ export const applyCouponCode = async ({ checkoutEntityId, couponCode }: Props) = const checkout = response.data.checkout.applyCheckoutCoupon?.checkout; - revalidateTag(TAGS.checkout); + revalidateTag(TAGS.checkout, { expire: 0 }); return checkout; }; diff --git a/core/app/[locale]/(default)/cart/_actions/apply-gift-certificate.ts b/core/app/[locale]/(default)/cart/_actions/apply-gift-certificate.ts index b2133c65c6..23113eef8b 100644 --- a/core/app/[locale]/(default)/cart/_actions/apply-gift-certificate.ts +++ b/core/app/[locale]/(default)/cart/_actions/apply-gift-certificate.ts @@ -47,7 +47,7 @@ export const applyGiftCertificate = async ({ checkoutEntityId, giftCertificateCo const checkout = response.data.checkout.applyCheckoutGiftCertificate?.checkout; - revalidateTag(TAGS.checkout); + revalidateTag(TAGS.checkout, { expire: 0 }); return checkout; }; diff --git a/core/app/[locale]/(default)/cart/_actions/remove-coupon-code.ts b/core/app/[locale]/(default)/cart/_actions/remove-coupon-code.ts index 9d0ef45efa..b27a956fdd 100644 --- a/core/app/[locale]/(default)/cart/_actions/remove-coupon-code.ts +++ b/core/app/[locale]/(default)/cart/_actions/remove-coupon-code.ts @@ -45,7 +45,7 @@ export const removeCouponCode = async ({ checkoutEntityId, couponCode }: Props) const checkout = response.data.checkout.unapplyCheckoutCoupon?.checkout; - revalidateTag(TAGS.checkout); + revalidateTag(TAGS.checkout, { expire: 0 }); return checkout; }; diff --git a/core/app/[locale]/(default)/cart/_actions/remove-gift-certificate.ts b/core/app/[locale]/(default)/cart/_actions/remove-gift-certificate.ts index 1d358ae1a9..040d97a1fc 100644 --- a/core/app/[locale]/(default)/cart/_actions/remove-gift-certificate.ts +++ b/core/app/[locale]/(default)/cart/_actions/remove-gift-certificate.ts @@ -47,7 +47,7 @@ export const removeGiftCertificate = async ({ checkoutEntityId, giftCertificateC const checkout = response.data.checkout.unapplyCheckoutGiftCertificate?.checkout; - revalidateTag(TAGS.checkout); + revalidateTag(TAGS.checkout, { expire: 0 }); return checkout; }; diff --git a/core/app/[locale]/(default)/cart/_actions/remove-item.ts b/core/app/[locale]/(default)/cart/_actions/remove-item.ts index f02a24dd66..fd4ee07fe8 100644 --- a/core/app/[locale]/(default)/cart/_actions/remove-item.ts +++ b/core/app/[locale]/(default)/cart/_actions/remove-item.ts @@ -1,6 +1,6 @@ 'use server'; -import { unstable_expireTag } from 'next/cache'; +import { revalidateTag } from 'next/cache'; import { getTranslations } from 'next-intl/server'; import { getSessionCustomerAccessToken } from '~/auth'; @@ -62,7 +62,7 @@ export async function removeItem({ await clearCartId(); } - unstable_expireTag(TAGS.cart); + revalidateTag(TAGS.cart, { expire: 0 }); return cart; } diff --git a/core/app/[locale]/(default)/product/[slug]/_actions/wishlist-action.ts b/core/app/[locale]/(default)/product/[slug]/_actions/wishlist-action.ts index faa4368e3d..385ab2d74f 100644 --- a/core/app/[locale]/(default)/product/[slug]/_actions/wishlist-action.ts +++ b/core/app/[locale]/(default)/product/[slug]/_actions/wishlist-action.ts @@ -235,7 +235,7 @@ export async function wishlistAction(payload: FormData): Promise { } } - revalidateTag(TAGS.customer); + revalidateTag(TAGS.customer, { expire: 0 }); } catch (error) { // eslint-disable-next-line no-console console.error(error); diff --git a/core/components/header/_actions/switch-currency.ts b/core/components/header/_actions/switch-currency.ts index 93cbec4f80..b15b87d72f 100644 --- a/core/components/header/_actions/switch-currency.ts +++ b/core/components/header/_actions/switch-currency.ts @@ -64,7 +64,7 @@ export const switchCurrency = async (_prevState: SubmissionResult | null, payloa if (cartId) { await updateCartCurrency(cartId, submission.value.id) .then(() => { - revalidateTag(TAGS.cart); + revalidateTag(TAGS.cart, { expire: 0 }); }) .catch((error: unknown) => { // eslint-disable-next-line no-console diff --git a/core/lib/cart/index.ts b/core/lib/cart/index.ts index 8e1c74d1c7..876f9a56c0 100644 --- a/core/lib/cart/index.ts +++ b/core/lib/cart/index.ts @@ -1,6 +1,6 @@ 'use server'; -import { unstable_expireTag } from 'next/cache'; +import { revalidateTag } from 'next/cache'; import { auth, getAnonymousSession, updateAnonymousSession, updateSession } from '~/auth'; import { TAGS } from '~/client/tags'; @@ -59,7 +59,7 @@ export async function addToOrCreateCart( throw new MissingCartError(); } - unstable_expireTag(TAGS.cart); + revalidateTag(TAGS.cart, { expire: 0 }); return; } @@ -72,5 +72,5 @@ export async function addToOrCreateCart( await setCartId(createResponse.data.cart.createCart.cart.entityId); - unstable_expireTag(TAGS.cart); + revalidateTag(TAGS.cart, { expire: 0 }); } diff --git a/core/vibes/soul/sections/product-detail/actions/revalidate-cart.ts b/core/vibes/soul/sections/product-detail/actions/revalidate-cart.ts index ea59472e80..c5e199ad1c 100644 --- a/core/vibes/soul/sections/product-detail/actions/revalidate-cart.ts +++ b/core/vibes/soul/sections/product-detail/actions/revalidate-cart.ts @@ -5,4 +5,4 @@ import { revalidateTag } from 'next/cache'; import { TAGS } from '~/client/tags'; // eslint-disable-next-line @typescript-eslint/require-await -export const revalidateCart = async () => revalidateTag(TAGS.cart); +export const revalidateCart = async () => revalidateTag(TAGS.cart, { expire: 0 }); From 8d9dee6c33ad2d9475facbcbf2a9ef860d6dc615 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 24 Feb 2026 16:31:21 -0600 Subject: [PATCH 04/24] refactor(core): replace unstable_expirePath with revalidatePath --- core/app/[locale]/(default)/cart/_actions/update-quantity.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/app/[locale]/(default)/cart/_actions/update-quantity.ts b/core/app/[locale]/(default)/cart/_actions/update-quantity.ts index 6a36c88c60..ebae4492ed 100644 --- a/core/app/[locale]/(default)/cart/_actions/update-quantity.ts +++ b/core/app/[locale]/(default)/cart/_actions/update-quantity.ts @@ -1,6 +1,6 @@ 'use server'; -import { unstable_expirePath } from 'next/cache'; +import { revalidatePath } from 'next/cache'; import { getTranslations } from 'next-intl/server'; import { getSessionCustomerAccessToken } from '~/auth'; @@ -87,7 +87,7 @@ export const updateQuantity = async ({ throw new Error(t('failedToUpdateQuantity')); } - unstable_expirePath('/cart'); + revalidatePath('/cart'); return cart; }; From 4f272d3374923b2299ca5d08c2e23b0fc5af8b5e Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 24 Feb 2026 16:31:33 -0600 Subject: [PATCH 05/24] chore(core): update tsconfig for next.js 16 Change jsx from "preserve" to "react-jsx" and add .next/dev/types to the include array for generated dev types. --- core/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/tsconfig.json b/core/tsconfig.json index ba1c5882a1..ebee1d5204 100644 --- a/core/tsconfig.json +++ b/core/tsconfig.json @@ -14,7 +14,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -48,6 +48,7 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", "tests/**/*" ], "exclude": ["node_modules", ".next"] From 06c4b3843608ab53d594bca9aebc0fbab4b9f9b0 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 3 Mar 2026 17:29:15 -0600 Subject: [PATCH 06/24] fix(core): resolve Next.js 16 deprecation lint errors Replace `NextMiddleware` with `NextProxy` and `priority` with `preload` on Image components per Next.js 16 API changes. --- core/middlewares/compose-middlewares.ts | 6 +++--- core/vibes/soul/primitives/product-card/index.tsx | 2 +- core/vibes/soul/sections/product-detail/product-gallery.tsx | 2 +- core/vibes/soul/sections/slideshow/index.tsx | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/middlewares/compose-middlewares.ts b/core/middlewares/compose-middlewares.ts index ebcd8daae5..14eb0f7f65 100644 --- a/core/middlewares/compose-middlewares.ts +++ b/core/middlewares/compose-middlewares.ts @@ -1,11 +1,11 @@ -import { type NextMiddleware, NextResponse } from 'next/server'; +import { type NextProxy, NextResponse } from 'next/server'; -export type MiddlewareFactory = (middleware: NextMiddleware) => NextMiddleware; +export type MiddlewareFactory = (middleware: NextProxy) => NextProxy; export const composeMiddlewares = ( firstMiddlewareWrapper: MiddlewareFactory, ...otherMiddlewareWrappers: MiddlewareFactory[] -): NextMiddleware => { +): NextProxy => { const middlewares = otherMiddlewareWrappers.reduce( (accumulatedMiddlewares, nextMiddleware) => (middleware) => accumulatedMiddlewares(nextMiddleware(middleware)), diff --git a/core/vibes/soul/primitives/product-card/index.tsx b/core/vibes/soul/primitives/product-card/index.tsx index 5a87d88725..1571440471 100644 --- a/core/vibes/soul/primitives/product-card/index.tsx +++ b/core/vibes/soul/primitives/product-card/index.tsx @@ -114,7 +114,7 @@ export function ProductCard({ }[colorScheme], )} fill - priority={imagePriority} + preload={imagePriority} sizes={imageSizes} src={image.src} /> diff --git a/core/vibes/soul/sections/product-detail/product-gallery.tsx b/core/vibes/soul/sections/product-detail/product-gallery.tsx index be9d0db905..b11c42cea3 100644 --- a/core/vibes/soul/sections/product-detail/product-gallery.tsx +++ b/core/vibes/soul/sections/product-detail/product-gallery.tsx @@ -269,7 +269,7 @@ export function ProductGallery({ }[fit], )} fill - priority={idx === 0} + preload={idx === 0} sizes="(min-width: 42rem) 50vw, 100vw" src={image.src} /> diff --git a/core/vibes/soul/sections/slideshow/index.tsx b/core/vibes/soul/sections/slideshow/index.tsx index f98a1c5fa3..708572965d 100644 --- a/core/vibes/soul/sections/slideshow/index.tsx +++ b/core/vibes/soul/sections/slideshow/index.tsx @@ -199,7 +199,7 @@ export function Slideshow({ slides, playOnInit = true, interval = 5000, classNam placeholder={ image.blurDataUrl != null && image.blurDataUrl !== '' ? 'blur' : 'empty' } - priority={idx === 0} + preload={idx === 0} sizes="100vw" src={image.src} /> From c50e7a703be157cf570a813a86cb9dfeea2fe978 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 3 Mar 2026 14:10:51 -0600 Subject: [PATCH 07/24] feat(core): add X-Correlation-ID header, cache guest queries separately --- .gitignore | 1 + .../(auth)/change-password/page-data.ts | 33 ++- .../(faceted)/brand/[slug]/page-data.ts | 38 +++- .../(faceted)/category/[slug]/page-data.ts | 36 ++- .../(faceted)/fetch-compare-products.ts | 36 ++- .../(faceted)/fetch-faceted-search.ts | 90 +++++++- .../(default)/(faceted)/search/page-data.ts | 23 +- .../(default)/blog/[blogId]/page-data.ts | 34 ++- core/app/[locale]/(default)/blog/page-data.ts | 60 ++++- core/app/[locale]/(default)/cart/page-data.ts | 23 +- .../[locale]/(default)/compare/page-data.ts | 38 +++- .../(default)/gift-certificates/page-data.ts | 32 ++- .../gift-certificates/purchase/page-data.ts | 34 ++- core/app/[locale]/(default)/page-data.ts | 30 ++- .../(default)/product/[slug]/page-data.ts | 210 +++++++++++++++--- .../webpages/[id]/contact/page-data.ts | 24 +- .../webpages/[id]/normal/page-data.ts | 24 +- .../(default)/wishlist/[token]/page-data.ts | 46 ++-- core/client/correlation-id.ts | 8 + core/client/index.ts | 3 + 20 files changed, 665 insertions(+), 158 deletions(-) create mode 100644 core/client/correlation-id.ts diff --git a/.gitignore b/.gitignore index a0caaaaac9..959b63145c 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ coverage/ .history .unlighthouse .bigcommerce +.worktrees diff --git a/core/app/[locale]/(default)/(auth)/change-password/page-data.ts b/core/app/[locale]/(default)/(auth)/change-password/page-data.ts index 43a72f2d3a..fff64127f6 100644 --- a/core/app/[locale]/(default)/(auth)/change-password/page-data.ts +++ b/core/app/[locale]/(default)/(auth)/change-password/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -24,16 +26,27 @@ const ChangePasswordQuery = graphql(` } `); -export const getChangePasswordQuery = cache(async () => { - const response = await client.fetch({ - document: ChangePasswordQuery, - fetchOptions: { next: { revalidate } }, - }); +const getCachedChangePasswordQuery = unstable_cache( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async (_locale: string) => { + const response = await client.fetch({ + document: ChangePasswordQuery, + fetchOptions: { cache: 'no-store' }, + }); + + const passwordComplexitySettings = + response.data.site.settings?.customers?.passwordComplexitySettings; - const passwordComplexitySettings = - response.data.site.settings?.customers?.passwordComplexitySettings; + return { + passwordComplexitySettings, + }; + }, + ['get-change-password-query'], + { revalidate }, +); + +export const getChangePasswordQuery = cache(async () => { + const locale = await getLocale(); - return { - passwordComplexitySettings, - }; + return getCachedChangePasswordQuery(locale); }); diff --git a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts index 9bb605d215..6e63a45abf 100644 --- a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -38,13 +40,33 @@ const BrandPageQuery = graphql(` } `); +const getCachedBrandPageData = unstable_cache( + async (_locale: string, entityId: number) => { + const response = await client.fetch({ + document: BrandPageQuery, + variables: { entityId }, + fetchOptions: { cache: 'no-store' }, + }); + + return response.data.site; + }, + ['get-brand-page-data'], + { revalidate }, +); + export const getBrandPageData = cache(async (entityId: number, customerAccessToken?: string) => { - const response = await client.fetch({ - document: BrandPageQuery, - variables: { entityId }, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, - }); - - return response.data.site; + if (customerAccessToken) { + const response = await client.fetch({ + document: BrandPageQuery, + variables: { entityId }, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return response.data.site; + } + + const locale = await getLocale(); + + return getCachedBrandPageData(locale, entityId); }); diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts index 6c2c4633fe..7d20358909 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -58,13 +60,33 @@ const CategoryPageQuery = graphql( [BreadcrumbsCategoryFragment], ); +const getCachedCategoryPageData = unstable_cache( + async (_locale: string, entityId: number) => { + const response = await client.fetch({ + document: CategoryPageQuery, + variables: { entityId }, + fetchOptions: { cache: 'no-store' }, + }); + + return response.data.site; + }, + ['get-category-page-data'], + { revalidate }, +); + export const getCategoryPageData = cache(async (entityId: number, customerAccessToken?: string) => { - const response = await client.fetch({ - document: CategoryPageQuery, - variables: { entityId }, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, - }); + if (customerAccessToken) { + const response = await client.fetch({ + document: CategoryPageQuery, + variables: { entityId }, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return response.data.site; + } + + const locale = await getLocale(); - return response.data.site; + return getCachedCategoryPageData(locale, entityId); }); diff --git a/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts b/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts index 8033dc8235..e806d86624 100644 --- a/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts +++ b/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts @@ -1,5 +1,7 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { VariablesOf } from 'gql.tada'; +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { z } from 'zod'; @@ -42,8 +44,8 @@ const CompareProductsQuery = graphql(` type Variables = VariablesOf; -export const getCompareProducts = cache( - async (variables: Variables, customerAccessToken?: string) => { +const getCachedCompareProducts = unstable_cache( + async (_locale: string, variables: Variables) => { const parsedVariables = CompareProductsSchema.parse(variables); if (parsedVariables.entityIds.length === 0) { @@ -53,10 +55,36 @@ export const getCompareProducts = cache( const response = await client.fetch({ document: CompareProductsQuery, variables: { ...parsedVariables, first: MAX_COMPARE_LIMIT }, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); return removeEdgesAndNodes(response.data.site.products); }, + ['get-compare-products'], + { revalidate }, +); + +export const getCompareProducts = cache( + async (variables: Variables, customerAccessToken?: string) => { + if (customerAccessToken) { + const parsedVariables = CompareProductsSchema.parse(variables); + + if (parsedVariables.entityIds.length === 0) { + return []; + } + + const response = await client.fetch({ + document: CompareProductsQuery, + variables: { ...parsedVariables, first: MAX_COMPARE_LIMIT }, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return removeEdgesAndNodes(response.data.site.products); + } + + const locale = await getLocale(); + + return getCachedCompareProducts(locale, variables); + }, ); diff --git a/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts b/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts index 115d639d1c..719e5decdb 100644 --- a/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts +++ b/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts @@ -1,4 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { z } from 'zod'; @@ -178,11 +180,11 @@ interface ProductSearch { filters: SearchProductsFiltersInput; } -const getProductSearchResults = cache( +const getCachedProductSearchResults = unstable_cache( async ( + _locale: string, { limit = 9, after, before, sort, filters }: ProductSearch, - currencyCode?: CurrencyCode, - customerAccessToken?: string, + currencyCode: CurrencyCode | undefined, ) => { const filterArgs = { filters, sort }; const paginationArgs = before ? { last: limit, before } : { first: limit, after }; @@ -190,12 +192,10 @@ const getProductSearchResults = cache( const response = await client.fetch({ document: GetProductSearchResultsQuery, variables: { ...filterArgs, ...paginationArgs, currencyCode }, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate: 300 } }, + fetchOptions: { cache: 'no-store' }, }); const { site } = response.data; - const searchResults = site.search.searchProducts; const items = removeEdgesAndNodes(searchResults.products).map((product) => ({ @@ -242,6 +242,84 @@ const getProductSearchResults = cache( }, }; }, + ['get-product-search-results'], + { revalidate: 300 }, +); + +const getProductSearchResults = cache( + // We need to make sure the reference passed into this function is the same if we want it to be memoized. + async ( + { limit = 9, after, before, sort, filters }: ProductSearch, + currencyCode?: CurrencyCode, + customerAccessToken?: string, + ) => { + if (customerAccessToken) { + const filterArgs = { filters, sort }; + const paginationArgs = before ? { last: limit, before } : { first: limit, after }; + + const response = await client.fetch({ + document: GetProductSearchResultsQuery, + variables: { ...filterArgs, ...paginationArgs, currencyCode }, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + const { site } = response.data; + const searchResults = site.search.searchProducts; + + const items = removeEdgesAndNodes(searchResults.products).map((product) => ({ + ...product, + })); + + return { + facets: { + items: removeEdgesAndNodes(searchResults.filters).map((node) => { + switch (node.__typename) { + case 'BrandSearchFilter': + return { + ...node, + brands: removeEdgesAndNodes(node.brands), + }; + + case 'CategorySearchFilter': + return { + ...node, + categories: removeEdgesAndNodes(node.categories), + }; + + case 'ProductAttributeSearchFilter': + return { + ...node, + attributes: removeEdgesAndNodes(node.attributes), + }; + + case 'RatingSearchFilter': + return { + ...node, + ratings: removeEdgesAndNodes(node.ratings), + }; + + default: + return node; + } + }), + }, + products: { + collectionInfo: searchResults.products.collectionInfo, + pageInfo: searchResults.products.pageInfo, + items, + }, + }; + } + + const locale = await getLocale(); + + return getCachedProductSearchResults( + locale, + { limit, after, before, sort, filters }, + currencyCode, + ); + }, ); const SearchParamSchema = z.union([z.string(), z.array(z.string()), z.undefined()]); diff --git a/core/app/[locale]/(default)/(faceted)/search/page-data.ts b/core/app/[locale]/(default)/(faceted)/search/page-data.ts index 37f571c49b..a28be9fe3f 100644 --- a/core/app/[locale]/(default)/(faceted)/search/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/search/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -29,11 +31,22 @@ const SearchPageQuery = graphql(` } `); +const getCachedSearchPageData = unstable_cache( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async (_locale: string) => { + const response = await client.fetch({ + document: SearchPageQuery, + fetchOptions: { cache: 'no-store' }, + }); + + return response.data.site; + }, + ['get-search-page-data'], + { revalidate }, +); + export const getSearchPageData = cache(async () => { - const response = await client.fetch({ - document: SearchPageQuery, - fetchOptions: { next: { revalidate } }, - }); + const locale = await getLocale(); - return response.data.site; + return getCachedSearchPageData(locale); }); diff --git a/core/app/[locale]/(default)/blog/[blogId]/page-data.ts b/core/app/[locale]/(default)/blog/[blogId]/page-data.ts index 472c44059a..c1b1213590 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/page-data.ts +++ b/core/app/[locale]/(default)/blog/[blogId]/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -38,18 +40,28 @@ const BlogPageQuery = graphql(` type Variables = VariablesOf; -export const getBlogPageData = cache(async (variables: Variables) => { - const response = await client.fetch({ - document: BlogPageQuery, - variables, - fetchOptions: { next: { revalidate } }, - }); +const getCachedBlogPageData = unstable_cache( + async (_locale: string, variables: Variables) => { + const response = await client.fetch({ + document: BlogPageQuery, + variables, + fetchOptions: { cache: 'no-store' }, + }); - const { blog } = response.data.site.content; + const { blog } = response.data.site.content; - if (!blog?.post) { - return null; - } + if (!blog?.post) { + return null; + } + + return blog; + }, + ['get-blog-page-data'], + { revalidate }, +); + +export const getBlogPageData = cache(async (variables: Variables) => { + const locale = await getLocale(); - return blog; + return getCachedBlogPageData(locale, variables); }); diff --git a/core/app/[locale]/(default)/blog/page-data.ts b/core/app/[locale]/(default)/blog/page-data.ts index d51cf024cd..575f003f66 100644 --- a/core/app/[locale]/(default)/blog/page-data.ts +++ b/core/app/[locale]/(default)/blog/page-data.ts @@ -1,5 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; -import { getFormatter } from 'next-intl/server'; +import { unstable_cache } from 'next/cache'; +import { getFormatter, getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -72,24 +73,38 @@ interface Pagination { after: string | null; } +const getCachedBlog = unstable_cache( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async (_locale: string) => { + const response = await client.fetch({ + document: BlogQuery, + fetchOptions: { cache: 'no-store' }, + }); + + return response.data.site.content.blog; + }, + ['get-blog'], + { revalidate }, +); + export const getBlog = cache(async () => { - const response = await client.fetch({ - document: BlogQuery, - fetchOptions: { next: { revalidate } }, - }); + const locale = await getLocale(); - return response.data.site.content.blog; + return getCachedBlog(locale); }); -export const getBlogPosts = cache( - async ({ tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination) => { +const getCachedBlogPosts = unstable_cache( + async ( + _locale: string, + { tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination, + ) => { const filterArgs = tag ? { filters: { tags: [tag] } } : {}; const paginationArgs = before ? { last: limit, before } : { first: limit, after }; const response = await client.fetch({ document: BlogPostsPageQuery, variables: { ...filterArgs, ...paginationArgs }, - fetchOptions: { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); const { blog } = response.data.site.content; @@ -98,15 +113,13 @@ export const getBlogPosts = cache( return null; } - const format = await getFormatter(); - return { pageInfo: blog.posts.pageInfo, posts: removeEdgesAndNodes(blog.posts).map((post) => ({ id: String(post.entityId), author: post.author, content: post.plainTextSummary, - date: format.dateTime(new Date(post.publishedDate.utc)), + dateUtc: post.publishedDate.utc, image: post.thumbnailImage ? { src: post.thumbnailImage.url, @@ -118,4 +131,27 @@ export const getBlogPosts = cache( })), }; }, + ['get-blog-posts'], + { revalidate }, +); + +export const getBlogPosts = cache( + async ({ tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination) => { + const locale = await getLocale(); + const raw = await getCachedBlogPosts(locale, { tag, limit, before, after }); + + if (!raw) { + return null; + } + + const format = await getFormatter(); + + return { + pageInfo: raw.pageInfo, + posts: raw.posts.map(({ dateUtc, ...post }) => ({ + ...post, + date: format.dateTime(new Date(dateUtc)), + })), + }; + }, ); diff --git a/core/app/[locale]/(default)/cart/page-data.ts b/core/app/[locale]/(default)/cart/page-data.ts index c6e47636dc..62ffc30dff 100644 --- a/core/app/[locale]/(default)/cart/page-data.ts +++ b/core/app/[locale]/(default)/cart/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { getSessionCustomerAccessToken } from '~/auth'; @@ -336,11 +338,22 @@ const SupportedShippingDestinationsQuery = graphql(` } `); +const getCachedShippingCountries = unstable_cache( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async (_locale: string) => { + const { data } = await client.fetch({ + document: SupportedShippingDestinationsQuery, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site.settings?.shipping?.supportedShippingDestinations.countries ?? []; + }, + ['get-shipping-countries'], + { revalidate }, +); + export const getShippingCountries = cache(async () => { - const { data } = await client.fetch({ - document: SupportedShippingDestinationsQuery, - fetchOptions: { next: { revalidate } }, - }); + const locale = await getLocale(); - return data.site.settings?.shipping?.supportedShippingDestinations.countries ?? []; + return getCachedShippingCountries(locale); }); diff --git a/core/app/[locale]/(default)/compare/page-data.ts b/core/app/[locale]/(default)/compare/page-data.ts index 9b0acac0f7..5620f06da5 100644 --- a/core/app/[locale]/(default)/compare/page-data.ts +++ b/core/app/[locale]/(default)/compare/page-data.ts @@ -1,4 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -55,8 +57,8 @@ const ComparedProductsQuery = graphql( [ProductCardFragment], ); -export const getComparedProducts = cache( - async (productIds: number[] = [], currencyCode?: CurrencyCode, customerAccessToken?: string) => { +const getCachedComparedProducts = unstable_cache( + async (_locale: string, productIds: number[], currencyCode: CurrencyCode | undefined) => { if (productIds.length === 0) { return []; } @@ -68,10 +70,38 @@ export const getComparedProducts = cache( first: productIds.length ? MAX_COMPARE_LIMIT : 0, currencyCode, }, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); return removeEdgesAndNodes(data.site.products); }, + ['get-compared-products'], + { revalidate }, +); + +export const getComparedProducts = cache( + async (productIds: number[] = [], currencyCode?: CurrencyCode, customerAccessToken?: string) => { + if (customerAccessToken) { + if (productIds.length === 0) { + return []; + } + + const { data } = await client.fetch({ + document: ComparedProductsQuery, + variables: { + entityIds: productIds, + first: productIds.length ? MAX_COMPARE_LIMIT : 0, + currencyCode, + }, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return removeEdgesAndNodes(data.site.products); + } + + const locale = await getLocale(); + + return getCachedComparedProducts(locale, productIds, currencyCode); + }, ); diff --git a/core/app/[locale]/(default)/gift-certificates/page-data.ts b/core/app/[locale]/(default)/gift-certificates/page-data.ts index 6905ee0b7f..daaf33c0f1 100644 --- a/core/app/[locale]/(default)/gift-certificates/page-data.ts +++ b/core/app/[locale]/(default)/gift-certificates/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -26,16 +28,26 @@ const GiftCertificatesRootQuery = graphql( [StoreLogoFragment], ); +const getCachedGiftCertificatesData = unstable_cache( + async (_locale: string, currencyCode: CurrencyCode | undefined) => { + const response = await client.fetch({ + document: GiftCertificatesRootQuery, + variables: { currencyCode }, + fetchOptions: { cache: 'no-store' }, + }); + + return { + giftCertificatesEnabled: response.data.site.settings?.giftCertificates?.isEnabled ?? false, + defaultCurrency: response.data.site.settings?.currency.defaultCurrency ?? undefined, + logo: response.data.site.settings ? logoTransformer(response.data.site.settings) : '', + }; + }, + ['get-gift-certificates-data'], + { revalidate }, +); + export const getGiftCertificatesData = cache(async (currencyCode?: CurrencyCode) => { - const response = await client.fetch({ - document: GiftCertificatesRootQuery, - variables: { currencyCode }, - fetchOptions: { next: { revalidate } }, - }); + const locale = await getLocale(); - return { - giftCertificatesEnabled: response.data.site.settings?.giftCertificates?.isEnabled ?? false, - defaultCurrency: response.data.site.settings?.currency.defaultCurrency ?? undefined, - logo: response.data.site.settings ? logoTransformer(response.data.site.settings) : '', - }; + return getCachedGiftCertificatesData(locale, currencyCode); }); diff --git a/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts b/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts index 609584722a..ebda9f09a8 100644 --- a/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts +++ b/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -29,17 +31,27 @@ const GiftCertificatePurchaseSettingsQuery = graphql( [GiftCertificateSettingsFragment, StoreLogoFragment], ); +const getCachedGiftCertificatePurchaseData = unstable_cache( + async (_locale: string, currencyCode: CurrencyCode | undefined) => { + const response = await client.fetch({ + document: GiftCertificatePurchaseSettingsQuery, + variables: { currencyCode }, + fetchOptions: { cache: 'no-store' }, + }); + + return { + giftCertificateSettings: response.data.site.settings?.giftCertificates ?? null, + logo: response.data.site.settings ? logoTransformer(response.data.site.settings) : '', + storeName: response.data.site.settings?.storeName ?? undefined, + defaultCurrency: response.data.site.settings?.currency.defaultCurrency ?? undefined, + }; + }, + ['get-gift-certificate-purchase-data'], + { revalidate }, +); + export const getGiftCertificatePurchaseData = cache(async (currencyCode?: CurrencyCode) => { - const response = await client.fetch({ - document: GiftCertificatePurchaseSettingsQuery, - variables: { currencyCode }, - fetchOptions: { next: { revalidate } }, - }); + const locale = await getLocale(); - return { - giftCertificateSettings: response.data.site.settings?.giftCertificates ?? null, - logo: response.data.site.settings ? logoTransformer(response.data.site.settings) : '', - storeName: response.data.site.settings?.storeName ?? undefined, - defaultCurrency: response.data.site.settings?.currency.defaultCurrency ?? undefined, - }; + return getCachedGiftCertificatePurchaseData(locale, currencyCode); }); diff --git a/core/app/[locale]/(default)/page-data.ts b/core/app/[locale]/(default)/page-data.ts index ab78d520a6..b3b0b8a353 100644 --- a/core/app/[locale]/(default)/page-data.ts +++ b/core/app/[locale]/(default)/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -77,15 +79,35 @@ const HomePageQuery = graphql( [FeaturedProductsCarouselFragment, FeaturedProductsListFragment], ); -export const getPageData = cache( - async (currencyCode?: CurrencyCode, customerAccessToken?: string) => { +const getCachedPageData = unstable_cache( + async (_locale: string, currencyCode: CurrencyCode | undefined) => { const { data } = await client.fetch({ document: HomePageQuery, - customerAccessToken, variables: { currencyCode }, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); return data; }, + ['get-page-data'], + { revalidate }, +); + +export const getPageData = cache( + async (currencyCode?: CurrencyCode, customerAccessToken?: string) => { + if (customerAccessToken) { + const { data } = await client.fetch({ + document: HomePageQuery, + customerAccessToken, + variables: { currencyCode }, + fetchOptions: { cache: 'no-store' }, + }); + + return data; + } + + const locale = await getLocale(); + + return getCachedPageData(locale, currencyCode); + }, ); diff --git a/core/app/[locale]/(default)/product/[slug]/page-data.ts b/core/app/[locale]/(default)/product/[slug]/page-data.ts index 02a8293735..9204bbbfd1 100644 --- a/core/app/[locale]/(default)/product/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/product/[slug]/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -154,17 +156,37 @@ const ProductPageMetadataQuery = graphql(` } `); -export const getProductPageMetadata = cache( - async (entityId: number, customerAccessToken?: string) => { +const getCachedProductPageMetadata = unstable_cache( + async (_locale: string, entityId: number) => { const { data } = await client.fetch({ document: ProductPageMetadataQuery, variables: { entityId }, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); return data.site.product; }, + ['get-product-page-metadata'], + { revalidate }, +); + +export const getProductPageMetadata = cache( + async (entityId: number, customerAccessToken?: string) => { + if (customerAccessToken) { + const { data } = await client.fetch({ + document: ProductPageMetadataQuery, + variables: { entityId }, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site.product; + } + + const locale = await getLocale(); + + return getCachedProductPageMetadata(locale, entityId); + }, ); const ProductQuery = graphql( @@ -200,15 +222,35 @@ const ProductQuery = graphql( [ProductOptionsFragment], ); +const getCachedProduct = unstable_cache( + async (_locale: string, entityId: number) => { + const { data } = await client.fetch({ + document: ProductQuery, + variables: { entityId }, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site; + }, + ['get-product'], + { revalidate }, +); + export const getProduct = cache(async (entityId: number, customerAccessToken?: string) => { - const { data } = await client.fetch({ - document: ProductQuery, - variables: { entityId }, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, - }); - - return data.site; + if (customerAccessToken) { + const { data } = await client.fetch({ + document: ProductQuery, + variables: { entityId }, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site; + } + + const locale = await getLocale(); + + return getCachedProduct(locale, entityId); }); const StreamableProductVariantInventoryBySkuQuery = graphql(` @@ -249,17 +291,37 @@ const StreamableProductVariantInventoryBySkuQuery = graphql(` type VariantInventoryVariables = VariablesOf; -export const getStreamableProductVariantInventory = cache( - async (variables: VariantInventoryVariables, customerAccessToken?: string) => { +const getCachedStreamableProductVariantInventory = unstable_cache( + async (_locale: string, variables: VariantInventoryVariables) => { const { data } = await client.fetch({ document: StreamableProductVariantInventoryBySkuQuery, variables, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate: 60 } }, + fetchOptions: { cache: 'no-store' }, }); return data.site.product?.variants; }, + ['get-streamable-product-variant-inventory'], + { revalidate: 60 }, +); + +export const getStreamableProductVariantInventory = cache( + async (variables: VariantInventoryVariables, customerAccessToken?: string) => { + if (customerAccessToken) { + const { data } = await client.fetch({ + document: StreamableProductVariantInventoryBySkuQuery, + variables, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site.product?.variants; + } + + const locale = await getLocale(); + + return getCachedStreamableProductVariantInventory(locale, variables); + }, ); const StreamableProductQuery = graphql( @@ -322,17 +384,37 @@ const StreamableProductQuery = graphql( type Variables = VariablesOf; -export const getStreamableProduct = cache( - async (variables: Variables, customerAccessToken?: string) => { +const getCachedStreamableProduct = unstable_cache( + async (_locale: string, variables: Variables) => { const { data } = await client.fetch({ document: StreamableProductQuery, variables, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); return data.site.product; }, + ['get-streamable-product'], + { revalidate }, +); + +export const getStreamableProduct = cache( + async (variables: Variables, customerAccessToken?: string) => { + if (customerAccessToken) { + const { data } = await client.fetch({ + document: StreamableProductQuery, + variables, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site.product; + } + + const locale = await getLocale(); + + return getCachedStreamableProduct(locale, variables); + }, ); const StreamableProductInventoryQuery = graphql( @@ -365,17 +447,37 @@ const StreamableProductInventoryQuery = graphql( type ProductInventoryVariables = VariablesOf; -export const getStreamableProductInventory = cache( - async (variables: ProductInventoryVariables, customerAccessToken?: string) => { +const getCachedStreamableProductInventory = unstable_cache( + async (_locale: string, variables: ProductInventoryVariables) => { const { data } = await client.fetch({ document: StreamableProductInventoryQuery, variables, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate: 60 } }, + fetchOptions: { cache: 'no-store' }, }); return data.site.product; }, + ['get-streamable-product-inventory'], + { revalidate: 60 }, +); + +export const getStreamableProductInventory = cache( + async (variables: ProductInventoryVariables, customerAccessToken?: string) => { + if (customerAccessToken) { + const { data } = await client.fetch({ + document: StreamableProductInventoryQuery, + variables, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site.product; + } + + const locale = await getLocale(); + + return getCachedStreamableProductInventory(locale, variables); + }, ); // Fields that require currencyCode as a query variable @@ -409,17 +511,37 @@ const ProductPricingAndRelatedProductsQuery = graphql( [PricingFragment, FeaturedProductsCarouselFragment], ); -export const getProductPricingAndRelatedProducts = cache( - async (variables: Variables, customerAccessToken?: string) => { +const getCachedProductPricingAndRelatedProducts = unstable_cache( + async (_locale: string, variables: Variables) => { const { data } = await client.fetch({ document: ProductPricingAndRelatedProductsQuery, variables, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); return data.site.product; }, + ['get-product-pricing-and-related-products'], + { revalidate }, +); + +export const getProductPricingAndRelatedProducts = cache( + async (variables: Variables, customerAccessToken?: string) => { + if (customerAccessToken) { + const { data } = await client.fetch({ + document: ProductPricingAndRelatedProductsQuery, + variables, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site.product; + } + + const locale = await getLocale(); + + return getCachedProductPricingAndRelatedProducts(locale, variables); + }, ); const InventorySettingsQuery = graphql(` @@ -440,12 +562,32 @@ const InventorySettingsQuery = graphql(` } `); +const getCachedStreamableInventorySettingsQuery = unstable_cache( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async (_locale: string) => { + const { data } = await client.fetch({ + document: InventorySettingsQuery, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site.settings?.inventory; + }, + ['get-streamable-inventory-settings'], + { revalidate }, +); + export const getStreamableInventorySettingsQuery = cache(async (customerAccessToken?: string) => { - const { data } = await client.fetch({ - document: InventorySettingsQuery, - customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, - }); + if (customerAccessToken) { + const { data } = await client.fetch({ + document: InventorySettingsQuery, + customerAccessToken, + fetchOptions: { cache: 'no-store' }, + }); + + return data.site.settings?.inventory; + } + + const locale = await getLocale(); - return data.site.settings?.inventory; + return getCachedStreamableInventorySettingsQuery(locale); }); 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..dbabff46f1 100644 --- a/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -31,12 +33,22 @@ const ContactPageQuery = graphql( type Variables = VariablesOf; +const getCachedWebpageData = unstable_cache( + async (_locale: string, variables: Variables) => { + const { data } = await client.fetch({ + document: ContactPageQuery, + variables, + fetchOptions: { cache: 'no-store' }, + }); + + return data; + }, + ['get-contact-webpage-data'], + { revalidate }, +); + export const getWebpageData = cache(async (variables: Variables) => { - const { data } = await client.fetch({ - document: ContactPageQuery, - variables, - fetchOptions: { next: { revalidate } }, - }); + const locale = await getLocale(); - return data; + return getCachedWebpageData(locale, variables); }); 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..ea924b35a9 100644 --- a/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -29,12 +31,22 @@ const NormalPageQuery = graphql( type Variables = VariablesOf; +const getCachedWebpageData = unstable_cache( + async (_locale: string, variables: Variables) => { + const { data } = await client.fetch({ + document: NormalPageQuery, + variables, + fetchOptions: { cache: 'no-store' }, + }); + + return data; + }, + ['get-normal-webpage-data'], + { revalidate }, +); + export const getWebpageData = cache(async (variables: Variables) => { - const { data } = await client.fetch({ - document: NormalPageQuery, - variables, - fetchOptions: { next: { revalidate } }, - }); + const locale = await getLocale(); - return data; + return getCachedWebpageData(locale, variables); }); diff --git a/core/app/[locale]/(default)/wishlist/[token]/page-data.ts b/core/app/[locale]/(default)/wishlist/[token]/page-data.ts index 4c3e56de3d..51acdc92ba 100644 --- a/core/app/[locale]/(default)/wishlist/[token]/page-data.ts +++ b/core/app/[locale]/(default)/wishlist/[token]/page-data.ts @@ -1,3 +1,5 @@ +import { unstable_cache } from 'next/cache'; +import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -50,22 +52,36 @@ interface Pagination { after?: string | null; } -export const getPublicWishlist = cache(async (token: string, pagination: Pagination) => { - const { before, after, limit = 9 } = pagination; - const currencyCode = await getPreferredCurrencyCode(); - const paginationArgs = before ? { last: limit, before } : { first: limit, after }; - const response = await client.fetch({ - document: PublicWishlistQuery, - variables: { ...paginationArgs, currencyCode, token }, - // Since the wishlist is public, it's okay that we cache this request - fetchOptions: { next: { revalidate, tags: [TAGS.customer] } }, - }); +const getCachedPublicWishlist = unstable_cache( + async ( + _locale: string, + token: string, + pagination: Pagination, + currencyCode: string | undefined, + ) => { + const { before, after, limit = 9 } = pagination; + const paginationArgs = before ? { last: limit, before } : { first: limit, after }; + const response = await client.fetch({ + document: PublicWishlistQuery, + variables: { ...paginationArgs, currencyCode, token }, + fetchOptions: { cache: 'no-store' }, + }); + + const wishlist = response.data.site.publicWishlist; + + if (!wishlist) { + return null; + } - const wishlist = response.data.site.publicWishlist; + return wishlist; + }, + ['get-public-wishlist'], + { revalidate, tags: [TAGS.customer] }, +); - if (!wishlist) { - return null; - } +export const getPublicWishlist = cache(async (token: string, pagination: Pagination) => { + const currencyCode = await getPreferredCurrencyCode(); + const locale = await getLocale(); - return wishlist; + return getCachedPublicWishlist(locale, token, pagination, currencyCode); }); diff --git a/core/client/correlation-id.ts b/core/client/correlation-id.ts new file mode 100644 index 0000000000..f3ce208e1a --- /dev/null +++ b/core/client/correlation-id.ts @@ -0,0 +1,8 @@ +import { cache } from 'react'; + +/** + * Returns a stable correlation ID for the current request. + * React.cache ensures the same UUID is returned for all fetches within a + * single page render, while being unique across renders/requests. + */ +export const getCorrelationId = cache((): string => crypto.randomUUID()); diff --git a/core/client/index.ts b/core/client/index.ts index 51020b0053..cb5c73976c 100644 --- a/core/client/index.ts +++ b/core/client/index.ts @@ -13,6 +13,7 @@ import { backendUserAgent } from '../user-agent'; // During config resolution, the dynamic import of next-intl/server succeeds but // getLocale() throws ("not supported in Client Components") — the try/catch // below absorbs this gracefully, and getChannelId falls back to defaultChannelId. +import { getCorrelationId } from './correlation-id'; const getLocale = async () => { try { @@ -66,6 +67,8 @@ export const client = createClient({ requestHeaders['Accept-Language'] = locale; } + requestHeaders['X-Correlation-ID'] = getCorrelationId(); + return { headers: requestHeaders, }; From 107398b0158fa8fd1cf7dca8a7d05cfd42a45235 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 13:01:04 -0600 Subject: [PATCH 08/24] fix: use unstable_cache --- .../(auth)/change-password/page-data.ts | 10 +- .../(default)/(auth)/change-password/page.tsx | 2 +- .../(default)/(auth)/register/page-data.ts | 63 ++++++----- .../(default)/(auth)/register/page.tsx | 2 +- .../(faceted)/brand/[slug]/page-data.ts | 33 +++--- .../(default)/(faceted)/brand/[slug]/page.tsx | 27 +++-- .../(faceted)/category/[slug]/page-data.ts | 33 +++--- .../(faceted)/category/[slug]/page.tsx | 24 +++- .../(faceted)/fetch-compare-products.ts | 9 +- .../(faceted)/fetch-faceted-search.ts | 10 +- .../(default)/(faceted)/search/page-data.ts | 9 +- .../(default)/(faceted)/search/page.tsx | 13 ++- .../(default)/account/addresses/page-data.ts | 9 +- .../(default)/account/addresses/page.tsx | 22 ++-- .../(default)/account/orders/page-data.ts | 12 +- .../(default)/account/orders/page.tsx | 12 +- .../account/wishlists/[id]/page-data.ts | 44 ++++---- .../(default)/account/wishlists/[id]/page.tsx | 62 +++++++++-- .../(default)/account/wishlists/page-data.ts | 41 ++++--- .../(default)/account/wishlists/page.tsx | 39 ++++++- .../(default)/blog/[blogId]/page-data.ts | 8 +- .../[locale]/(default)/blog/[blogId]/page.tsx | 10 +- core/app/[locale]/(default)/blog/page-data.ts | 19 ++-- core/app/[locale]/(default)/blog/page.tsx | 16 +-- .../cart/_actions/update-coupon-code.ts | 9 +- .../cart/_actions/update-gift-certificate.ts | 9 +- .../cart/_actions/update-shipping-info.ts | 9 +- core/app/[locale]/(default)/cart/page-data.ts | 19 ++-- core/app/[locale]/(default)/cart/page.tsx | 25 +++-- .../[locale]/(default)/compare/page-data.ts | 14 ++- core/app/[locale]/(default)/compare/page.tsx | 14 ++- .../gift-certificates/balance/page.tsx | 2 +- .../(default)/gift-certificates/page-data.ts | 14 +-- .../(default)/gift-certificates/page.tsx | 2 +- .../gift-certificates/purchase/page-data.ts | 14 +-- .../gift-certificates/purchase/page.tsx | 2 +- core/app/[locale]/(default)/page-data.ts | 9 +- core/app/[locale]/(default)/page.tsx | 2 +- .../(default)/product/[slug]/page-data.ts | 104 +++++++++--------- .../(default)/product/[slug]/page.tsx | 22 ++-- .../webpages/[id]/contact/page-data.ts | 8 +- .../(default)/webpages/[id]/contact/page.tsx | 28 ++--- .../webpages/[id]/normal/page-data.ts | 8 +- .../(default)/webpages/[id]/normal/page.tsx | 14 +-- .../(default)/wishlist/[token]/page-data.ts | 26 ++--- .../(default)/wishlist/[token]/page.tsx | 45 ++++++-- core/client/index.ts | 29 +---- packages/client/src/client.ts | 17 ++- 48 files changed, 561 insertions(+), 413 deletions(-) diff --git a/core/app/[locale]/(default)/(auth)/change-password/page-data.ts b/core/app/[locale]/(default)/(auth)/change-password/page-data.ts index fff64127f6..c48ab1d1a4 100644 --- a/core/app/[locale]/(default)/(auth)/change-password/page-data.ts +++ b/core/app/[locale]/(default)/(auth)/change-password/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -27,11 +26,10 @@ const ChangePasswordQuery = graphql(` `); const getCachedChangePasswordQuery = unstable_cache( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async (_locale: string) => { + async (locale: string) => { const response = await client.fetch({ document: ChangePasswordQuery, - fetchOptions: { cache: 'no-store' }, + locale, }); const passwordComplexitySettings = @@ -45,8 +43,6 @@ const getCachedChangePasswordQuery = unstable_cache( { revalidate }, ); -export const getChangePasswordQuery = cache(async () => { - const locale = await getLocale(); - +export const getChangePasswordQuery = cache(async (locale: string) => { return getCachedChangePasswordQuery(locale); }); diff --git a/core/app/[locale]/(default)/(auth)/change-password/page.tsx b/core/app/[locale]/(default)/(auth)/change-password/page.tsx index 1e7e251a6a..fe8f70832d 100644 --- a/core/app/[locale]/(default)/(auth)/change-password/page.tsx +++ b/core/app/[locale]/(default)/(auth)/change-password/page.tsx @@ -38,7 +38,7 @@ export default async function ChangePassword({ params, searchParams }: Props) { return redirect({ href: '/login', locale }); } - const { passwordComplexitySettings } = await getChangePasswordQuery(); + const { passwordComplexitySettings } = await getChangePasswordQuery(locale); return ( { - const customerAccessToken = await getSessionCustomerAccessToken(); +const getCachedRegisterCustomerQuery = unstable_cache( + async (locale: string, { address, customer }: Props) => { + const response = await client.fetch({ + document: RegisterCustomerQuery, + variables: { + addressFilters: address?.filters, + addressSortBy: address?.sortBy, + customerFilters: customer?.filters, + customerSortBy: customer?.sortBy, + }, + fetchOptions: { cache: 'no-store' }, + locale, + }); - const response = await client.fetch({ - document: RegisterCustomerQuery, - variables: { - addressFilters: address?.filters, - addressSortBy: address?.sortBy, - customerFilters: customer?.filters, - customerSortBy: customer?.sortBy, - }, - fetchOptions: { cache: 'no-store' }, - customerAccessToken, - }); + const addressFields = response.data.site.settings?.formFields.shippingAddress; + const customerFields = response.data.site.settings?.formFields.customer; + const countries = response.data.geography.countries; + const passwordComplexitySettings = + response.data.site.settings?.customers?.passwordComplexitySettings; - const addressFields = response.data.site.settings?.formFields.shippingAddress; - const customerFields = response.data.site.settings?.formFields.customer; - const countries = response.data.geography.countries; - const passwordComplexitySettings = - response.data.site.settings?.customers?.passwordComplexitySettings; + if (!addressFields || !customerFields) { + return null; + } - if (!addressFields || !customerFields) { - return null; - } + return { + addressFields, + customerFields, + countries, + passwordComplexitySettings, + }; + }, + ['get-register-customer-query'], + { revalidate }, +); - return { - addressFields, - customerFields, - countries, - passwordComplexitySettings, - }; +export const getRegisterCustomerQuery = cache(async (locale: string, props: Props) => { + return getCachedRegisterCustomerQuery(locale, props); }); diff --git a/core/app/[locale]/(default)/(auth)/register/page.tsx b/core/app/[locale]/(default)/(auth)/register/page.tsx index bf8ebf1357..ea5fdc8a91 100644 --- a/core/app/[locale]/(default)/(auth)/register/page.tsx +++ b/core/app/[locale]/(default)/(auth)/register/page.tsx @@ -51,7 +51,7 @@ export default async function Register({ params }: Props) { const t = await getTranslations('Auth.Register'); - const registerCustomerData = await getRegisterCustomerQuery({ + const registerCustomerData = await getRegisterCustomerQuery(locale, { address: { sortBy: 'SORT_ORDER' }, customer: { sortBy: 'SORT_ORDER' }, }); diff --git a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts index 6e63a45abf..c7e0296921 100644 --- a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -41,10 +40,11 @@ const BrandPageQuery = graphql(` `); const getCachedBrandPageData = unstable_cache( - async (_locale: string, entityId: number) => { + async (locale: string, entityId: number) => { const response = await client.fetch({ document: BrandPageQuery, variables: { entityId }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -54,19 +54,20 @@ const getCachedBrandPageData = unstable_cache( { revalidate }, ); -export const getBrandPageData = cache(async (entityId: number, customerAccessToken?: string) => { - if (customerAccessToken) { - const response = await client.fetch({ - document: BrandPageQuery, - variables: { entityId }, - customerAccessToken, - fetchOptions: { cache: 'no-store' }, - }); +export const getBrandPageData = cache( + async (locale: string, entityId: number, customerAccessToken?: string) => { + if (customerAccessToken) { + const response = await client.fetch({ + document: BrandPageQuery, + variables: { entityId }, + customerAccessToken, + locale, + fetchOptions: { cache: 'no-store' }, + }); - return response.data.site; - } - - const locale = await getLocale(); + return response.data.site; + } - return getCachedBrandPageData(locale, entityId); -}); + return getCachedBrandPageData(locale, entityId); + }, +); diff --git a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx index 4278def31c..ba091c43ff 100644 --- a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx @@ -30,9 +30,14 @@ const getCachedBrand = cache((brandId: string) => { const compareLoader = createCompareLoader(); const createBrandSearchParamsLoader = cache( - async (brandId: string, customerAccessToken?: string) => { + async (locale: string, brandId: string, customerAccessToken?: string) => { const cachedBrand = getCachedBrand(brandId); - const brandSearch = await fetchFacetedSearch(cachedBrand, undefined, customerAccessToken); + const brandSearch = await fetchFacetedSearch( + locale, + cachedBrand, + undefined, + customerAccessToken, + ); const brandFacets = brandSearch.facets.items.filter( (facet) => facet.__typename !== 'BrandSearchFilter', ); @@ -73,7 +78,7 @@ export async function generateMetadata(props: Props): Promise { const brandId = Number(slug); - const { brand } = await getBrandPageData(brandId, customerAccessToken); + const { brand } = await getBrandPageData(locale, brandId, customerAccessToken); if (!brand) { return notFound(); @@ -99,7 +104,7 @@ export default async function Brand(props: Props) { const brandId = Number(slug); - const { brand, settings } = await getBrandPageData(brandId, customerAccessToken); + const { brand, settings } = await getBrandPageData(locale, brandId, customerAccessToken); if (!brand) { return notFound(); @@ -114,10 +119,11 @@ export default async function Brand(props: Props) { const searchParams = await props.searchParams; const currencyCode = await getPreferredCurrencyCode(); - const loadSearchParams = await createBrandSearchParamsLoader(slug, customerAccessToken); + const loadSearchParams = await createBrandSearchParamsLoader(locale, slug, customerAccessToken); const parsedSearchParams = loadSearchParams?.(searchParams) ?? {}; const search = await fetchFacetedSearch( + locale, { ...searchParams, ...parsedSearchParams, @@ -162,10 +168,15 @@ export default async function Brand(props: Props) { const streamableFilters = Streamable.from(async () => { const searchParams = await props.searchParams; - const loadSearchParams = await createBrandSearchParamsLoader(slug, customerAccessToken); + const loadSearchParams = await createBrandSearchParamsLoader(locale, slug, customerAccessToken); const parsedSearchParams = loadSearchParams?.(searchParams) ?? {}; const cachedBrand = getCachedBrand(slug); - const categorySearch = await fetchFacetedSearch(cachedBrand, undefined, customerAccessToken); + const categorySearch = await fetchFacetedSearch( + locale, + cachedBrand, + undefined, + customerAccessToken, + ); const refinedSearch = await streamableFacetedSearch; const allFacets = categorySearch.facets.items.filter( @@ -195,7 +206,7 @@ export default async function Brand(props: Props) { const compareIds = { entityIds: compare ? compare.map((id: string) => Number(id)) : [] }; - const products = await getCompareProductsData(compareIds, customerAccessToken); + const products = await getCompareProductsData(locale, compareIds, customerAccessToken); return products.map((product) => ({ id: product.entityId.toString(), diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts index 7d20358909..2e49f085d5 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -61,10 +60,11 @@ const CategoryPageQuery = graphql( ); const getCachedCategoryPageData = unstable_cache( - async (_locale: string, entityId: number) => { + async (locale: string, entityId: number) => { const response = await client.fetch({ document: CategoryPageQuery, variables: { entityId }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -74,19 +74,20 @@ const getCachedCategoryPageData = unstable_cache( { revalidate }, ); -export const getCategoryPageData = cache(async (entityId: number, customerAccessToken?: string) => { - if (customerAccessToken) { - const response = await client.fetch({ - document: CategoryPageQuery, - variables: { entityId }, - customerAccessToken, - fetchOptions: { cache: 'no-store' }, - }); +export const getCategoryPageData = cache( + async (locale: string, entityId: number, customerAccessToken?: string) => { + if (customerAccessToken) { + const response = await client.fetch({ + document: CategoryPageQuery, + variables: { entityId }, + customerAccessToken, + locale, + fetchOptions: { cache: 'no-store' }, + }); - return response.data.site; - } - - const locale = await getLocale(); + return response.data.site; + } - return getCachedCategoryPageData(locale, entityId); -}); + return getCachedCategoryPageData(locale, entityId); + }, +); diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx index ee143281b5..74c532cbb7 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx @@ -32,9 +32,14 @@ const getCachedCategory = cache((categoryId: number) => { const compareLoader = createCompareLoader(); const createCategorySearchParamsLoader = cache( - async (categoryId: number, customerAccessToken?: string) => { + async (locale: string, categoryId: number, customerAccessToken?: string) => { const cachedCategory = getCachedCategory(categoryId); - const categorySearch = await fetchFacetedSearch(cachedCategory, undefined, customerAccessToken); + const categorySearch = await fetchFacetedSearch( + locale, + cachedCategory, + undefined, + customerAccessToken, + ); const categoryFacets = categorySearch.facets.items.filter( (facet) => facet.__typename !== 'CategorySearchFilter', ); @@ -75,7 +80,7 @@ export async function generateMetadata(props: Props): Promise { const categoryId = Number(slug); - const { category } = await getCategoryPageData(categoryId, customerAccessToken); + const { category } = await getCategoryPageData(locale, categoryId, customerAccessToken); if (!category) { return notFound(); @@ -107,6 +112,7 @@ export default async function Category(props: Props) { const categoryId = Number(slug); const { category, settings, categoryTree } = await getCategoryPageData( + locale, categoryId, customerAccessToken, ); @@ -130,12 +136,14 @@ export default async function Category(props: Props) { const currencyCode = await getPreferredCurrencyCode(); const loadSearchParams = await createCategorySearchParamsLoader( + locale, categoryId, customerAccessToken, ); const parsedSearchParams = loadSearchParams?.(searchParams) ?? {}; const search = await fetchFacetedSearch( + locale, { ...searchParams, ...parsedSearchParams, @@ -182,12 +190,18 @@ export default async function Category(props: Props) { const searchParams = await props.searchParams; const loadSearchParams = await createCategorySearchParamsLoader( + locale, categoryId, customerAccessToken, ); const parsedSearchParams = loadSearchParams?.(searchParams) ?? {}; const cachedCategory = getCachedCategory(categoryId); - const categorySearch = await fetchFacetedSearch(cachedCategory, undefined, customerAccessToken); + const categorySearch = await fetchFacetedSearch( + locale, + cachedCategory, + undefined, + customerAccessToken, + ); const refinedSearch = await streamableFacetedSearch; const allFacets = categorySearch.facets.items.filter( @@ -234,7 +248,7 @@ export default async function Category(props: Props) { const compareIds = { entityIds: compare ? compare.map((id: string) => Number(id)) : [] }; - const products = await getCompareProducts(compareIds, customerAccessToken); + const products = await getCompareProducts(locale, compareIds, customerAccessToken); return products.map((product) => ({ id: product.entityId.toString(), diff --git a/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts b/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts index e806d86624..af4f0139ce 100644 --- a/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts +++ b/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts @@ -1,7 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { VariablesOf } from 'gql.tada'; import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { z } from 'zod'; @@ -45,7 +44,7 @@ const CompareProductsQuery = graphql(` type Variables = VariablesOf; const getCachedCompareProducts = unstable_cache( - async (_locale: string, variables: Variables) => { + async (locale: string, variables: Variables) => { const parsedVariables = CompareProductsSchema.parse(variables); if (parsedVariables.entityIds.length === 0) { @@ -55,6 +54,7 @@ const getCachedCompareProducts = unstable_cache( const response = await client.fetch({ document: CompareProductsQuery, variables: { ...parsedVariables, first: MAX_COMPARE_LIMIT }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -65,7 +65,7 @@ const getCachedCompareProducts = unstable_cache( ); export const getCompareProducts = cache( - async (variables: Variables, customerAccessToken?: string) => { + async (locale: string, variables: Variables, customerAccessToken?: string) => { if (customerAccessToken) { const parsedVariables = CompareProductsSchema.parse(variables); @@ -77,14 +77,13 @@ export const getCompareProducts = cache( document: CompareProductsQuery, variables: { ...parsedVariables, first: MAX_COMPARE_LIMIT }, customerAccessToken, + locale, fetchOptions: { cache: 'no-store' }, }); return removeEdgesAndNodes(response.data.site.products); } - const locale = await getLocale(); - return getCachedCompareProducts(locale, variables); }, ); diff --git a/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts b/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts index 719e5decdb..6c230abdc7 100644 --- a/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts +++ b/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts @@ -1,6 +1,5 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { z } from 'zod'; @@ -182,7 +181,7 @@ interface ProductSearch { const getCachedProductSearchResults = unstable_cache( async ( - _locale: string, + locale: string, { limit = 9, after, before, sort, filters }: ProductSearch, currencyCode: CurrencyCode | undefined, ) => { @@ -192,6 +191,7 @@ const getCachedProductSearchResults = unstable_cache( const response = await client.fetch({ document: GetProductSearchResultsQuery, variables: { ...filterArgs, ...paginationArgs, currencyCode }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -249,6 +249,7 @@ const getCachedProductSearchResults = unstable_cache( const getProductSearchResults = cache( // We need to make sure the reference passed into this function is the same if we want it to be memoized. async ( + locale: string, { limit = 9, after, before, sort, filters }: ProductSearch, currencyCode?: CurrencyCode, customerAccessToken?: string, @@ -261,6 +262,7 @@ const getProductSearchResults = cache( document: GetProductSearchResultsQuery, variables: { ...filterArgs, ...paginationArgs, currencyCode }, customerAccessToken, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -312,8 +314,6 @@ const getProductSearchResults = cache( }; } - const locale = await getLocale(); - return getCachedProductSearchResults( locale, { limit, after, before, sort, filters }, @@ -484,6 +484,7 @@ export const PublicToPrivateParams = PublicSearchParamsSchema.catchall(SearchPar export const fetchFacetedSearch = cache( // We need to make sure the reference passed into this function is the same if we want it to be memoized. async ( + locale: string, params: z.input, currencyCode?: CurrencyCode, customerAccessToken?: string, @@ -491,6 +492,7 @@ export const fetchFacetedSearch = cache( const { after, before, limit = 9, sort, filters } = PublicToPrivateParams.parse(params); return getProductSearchResults( + locale, { after, before, diff --git a/core/app/[locale]/(default)/(faceted)/search/page-data.ts b/core/app/[locale]/(default)/(faceted)/search/page-data.ts index a28be9fe3f..607832f973 100644 --- a/core/app/[locale]/(default)/(faceted)/search/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/search/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -32,10 +31,10 @@ const SearchPageQuery = graphql(` `); const getCachedSearchPageData = unstable_cache( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async (_locale: string) => { + async (locale: string) => { const response = await client.fetch({ document: SearchPageQuery, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -45,8 +44,6 @@ const getCachedSearchPageData = unstable_cache( { revalidate }, ); -export const getSearchPageData = cache(async () => { - const locale = await getLocale(); - +export const getSearchPageData = cache(async (locale: string) => { return getCachedSearchPageData(locale); }); diff --git a/core/app/[locale]/(default)/(faceted)/search/page.tsx b/core/app/[locale]/(default)/(faceted)/search/page.tsx index bc86471c32..d5f8007a34 100644 --- a/core/app/[locale]/(default)/(faceted)/search/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/search/page.tsx @@ -22,14 +22,14 @@ import { getSearchPageData } from './page-data'; const compareLoader = createCompareLoader(); const createSearchSearchParamsLoader = cache( - async (searchParams: SearchParams, customerAccessToken?: string) => { + async (locale: string, searchParams: SearchParams, customerAccessToken?: string) => { const searchTerm = typeof searchParams.term === 'string' ? searchParams.term : ''; if (!searchTerm) { return null; } - const search = await fetchFacetedSearch(searchParams, undefined, customerAccessToken); + const search = await fetchFacetedSearch(locale, searchParams, undefined, customerAccessToken); const searchFacets = search.facets.items; const transformedSearchFacets = await facetsTransformer({ refinedFacets: searchFacets, @@ -76,7 +76,7 @@ export default async function Search(props: Props) { const t = await getTranslations('Faceted'); - const { settings } = await getSearchPageData(); + const { settings } = await getSearchPageData(locale); const showRating = Boolean(settings?.reviews.enabled && settings.display.showProductRating); @@ -89,12 +89,14 @@ export default async function Search(props: Props) { const currencyCode = await getPreferredCurrencyCode(); const loadSearchParams = await createSearchSearchParamsLoader( + locale, searchParams, customerAccessToken, ); const parsedSearchParams = loadSearchParams?.(searchParams) ?? {}; const search = await fetchFacetedSearch( + locale, { ...searchParams, ...parsedSearchParams, @@ -186,11 +188,12 @@ export default async function Search(props: Props) { } const loadSearchParams = await createSearchSearchParamsLoader( + locale, searchParams, customerAccessToken, ); const parsedSearchParams = loadSearchParams?.(searchParams) ?? {}; - const categorySearch = await fetchFacetedSearch({}, undefined, customerAccessToken); + const categorySearch = await fetchFacetedSearch(locale, {}, undefined, customerAccessToken); const refinedSearch = await streamableFacetedSearch; const allFacets = categorySearch.facets.items.filter( @@ -221,7 +224,7 @@ export default async function Search(props: Props) { const compareIds = { entityIds: compare ? compare.map((id: string) => Number(id)) : [] }; - const products = await getCompareProductsData(compareIds, customerAccessToken); + const products = await getCompareProductsData(locale, compareIds, customerAccessToken); return products.map((product) => ({ id: product.entityId.toString(), diff --git a/core/app/[locale]/(default)/account/addresses/page-data.ts b/core/app/[locale]/(default)/account/addresses/page-data.ts index 66433985ff..f44e833967 100644 --- a/core/app/[locale]/(default)/account/addresses/page-data.ts +++ b/core/app/[locale]/(default)/account/addresses/page-data.ts @@ -1,7 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { cache } from 'react'; -import { getSessionCustomerAccessToken } from '~/auth'; import { client } from '~/client'; import { PaginationFragment } from '~/client/fragments/pagination'; import { graphql } from '~/client/graphql'; @@ -70,13 +69,17 @@ interface Pagination { } export const getCustomerAddresses = cache( - async ({ before = '', after = '', limit = 10 }: Pagination) => { - const customerAccessToken = await getSessionCustomerAccessToken(); + async ( + locale: string, + { before = '', after = '', limit = 10 }: Pagination, + customerAccessToken?: string, + ) => { const paginationArgs = before ? { last: limit, before } : { first: limit, after }; const response = await client.fetch({ document: GetCustomerAddressesQuery, variables: { ...paginationArgs }, + locale, customerAccessToken, fetchOptions: { cache: 'no-store', next: { tags: [TAGS.customer] } }, }); diff --git a/core/app/[locale]/(default)/account/addresses/page.tsx b/core/app/[locale]/(default)/account/addresses/page.tsx index 49c02451a6..865ba4f575 100644 --- a/core/app/[locale]/(default)/account/addresses/page.tsx +++ b/core/app/[locale]/(default)/account/addresses/page.tsx @@ -3,6 +3,7 @@ import { notFound } from 'next/navigation'; import { getTranslations, setRequestLocale } from 'next-intl/server'; import { Address, AddressListSection } from '@/vibes/soul/sections/address-list-section'; +import { getSessionCustomerAccessToken } from '~/auth'; import { formFieldTransformer, injectCountryCodeOptions, @@ -41,13 +42,20 @@ export default async function Addresses({ params, searchParams }: Props) { setRequestLocale(locale); - const t = await getTranslations('Account.Addresses'); - const { before, after } = await searchParams; - - const data = await getCustomerAddresses({ - ...(after && { after }), - ...(before && { before }), - }); + const [customerAccessToken, t, { before, after }] = await Promise.all([ + getSessionCustomerAccessToken(), + getTranslations('Account.Addresses'), + searchParams, + ]); + + const data = await getCustomerAddresses( + locale, + { + ...(after && { after }), + ...(before && { before }), + }, + customerAccessToken, + ); if (!data) { notFound(); diff --git a/core/app/[locale]/(default)/account/orders/page-data.ts b/core/app/[locale]/(default)/account/orders/page-data.ts index a2b240f4f4..bf67b08311 100644 --- a/core/app/[locale]/(default)/account/orders/page-data.ts +++ b/core/app/[locale]/(default)/account/orders/page-data.ts @@ -89,13 +89,10 @@ interface CustomerOrdersArgs { } export const getCustomerOrders = cache( - async ({ - before = '', - after = '', - filterByStatus, - filterByDateRange, - limit = 5, - }: CustomerOrdersArgs) => { + async ( + locale: string, + { before = '', after = '', filterByStatus, filterByDateRange, limit = 5 }: CustomerOrdersArgs, + ) => { const customerAccessToken = await getSessionCustomerAccessToken(); const paginationArgs = before ? { last: limit, before } : { first: limit, after }; const filtersArgs = { @@ -107,6 +104,7 @@ export const getCustomerOrders = cache( const response = await client.fetch({ document: CustomerAllOrders, variables: { ...paginationArgs, ...filtersArgs }, + locale, customerAccessToken, fetchOptions: { cache: 'no-store', next: { tags: [TAGS.customer] } }, errorPolicy: 'auth', diff --git a/core/app/[locale]/(default)/account/orders/page.tsx b/core/app/[locale]/(default)/account/orders/page.tsx index 65d4167426..aad96c1f18 100644 --- a/core/app/[locale]/(default)/account/orders/page.tsx +++ b/core/app/[locale]/(default)/account/orders/page.tsx @@ -15,9 +15,9 @@ interface Props { }>; } -async function getOrders(after?: string, before?: string): Promise { +async function getOrders(locale: string, after?: string, before?: string): Promise { const format = await getFormatter(); - const customerOrdersDetails = await getCustomerOrders({ + const customerOrdersDetails = await getCustomerOrders(locale, { ...(after && { after }), ...(before && { before }), }); @@ -31,8 +31,8 @@ async function getOrders(after?: string, before?: string): Promise { return ordersTransformer(orders, format); } -async function getPaginationInfo(after?: string, before?: string) { - const customerOrdersDetails = await getCustomerOrders({ +async function getPaginationInfo(locale: string, after?: string, before?: string) { + const customerOrdersDetails = await getCustomerOrders(locale, { ...(after && { after }), ...(before && { before }), }); @@ -53,8 +53,8 @@ export default async function Orders({ params, searchParams }: Props) { emptyStateActionLabel={t('EmptyState.cta')} emptyStateTitle={t('EmptyState.title')} orderNumberLabel={t('orderNumber')} - orders={getOrders(after, before)} - paginationInfo={getPaginationInfo(after, before)} + orders={getOrders(locale, after, before)} + paginationInfo={getPaginationInfo(locale, after, before)} title={t('title')} totalLabel={t('totalPrice')} viewDetailsLabel={t('viewDetails')} diff --git a/core/app/[locale]/(default)/account/wishlists/[id]/page-data.ts b/core/app/[locale]/(default)/account/wishlists/[id]/page-data.ts index ae14ab4173..602f3729bc 100644 --- a/core/app/[locale]/(default)/account/wishlists/[id]/page-data.ts +++ b/core/app/[locale]/(default)/account/wishlists/[id]/page-data.ts @@ -1,11 +1,10 @@ import { cache } from 'react'; -import { getSessionCustomerAccessToken } from '~/auth'; import { client } from '~/client'; import { graphql } from '~/client/graphql'; import { TAGS } from '~/client/tags'; +import type { CurrencyCode } from '~/components/header/fragment'; import { WishlistPaginatedItemsFragment } from '~/components/wishlist/fragment'; -import { getPreferredCurrencyCode } from '~/lib/currency'; const WishlistDetailsQuery = graphql( ` @@ -37,23 +36,30 @@ interface Pagination { after: string | null; } -export const getCustomerWishlist = cache(async (entityId: number, pagination: Pagination) => { - const { before, after, limit = 9 } = pagination; - const customerAccessToken = await getSessionCustomerAccessToken(); - const currencyCode = await getPreferredCurrencyCode(); - const paginationArgs = before ? { last: limit, before } : { first: limit, after }; - const response = await client.fetch({ - document: WishlistDetailsQuery, - variables: { ...paginationArgs, currencyCode, entityId }, - customerAccessToken, - fetchOptions: { cache: 'no-store', next: { tags: [TAGS.customer] } }, - }); +export const getCustomerWishlist = cache( + async ( + locale: string, + entityId: number, + pagination: Pagination, + customerAccessToken?: string, + currencyCode?: CurrencyCode, + ) => { + const { before, after, limit = 9 } = pagination; + const paginationArgs = before ? { last: limit, before } : { first: limit, after }; + const response = await client.fetch({ + document: WishlistDetailsQuery, + variables: { ...paginationArgs, currencyCode, entityId }, + locale, + customerAccessToken, + fetchOptions: { cache: 'no-store', next: { tags: [TAGS.customer] } }, + }); - const wishlist = response.data.customer?.wishlists.edges?.[0]?.node; + const wishlist = response.data.customer?.wishlists.edges?.[0]?.node; - if (!wishlist) { - return null; - } + if (!wishlist) { + return null; + } - return wishlist; -}); + return wishlist; + }, +); diff --git a/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx b/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx index 6ea2baa869..b55be1d869 100644 --- a/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx +++ b/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx @@ -6,10 +6,13 @@ import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/ser import { Streamable } from '@/vibes/soul/lib/streamable'; import { CursorPaginationInfo } from '@/vibes/soul/primitives/cursor-pagination'; import { Wishlist, WishlistDetails } from '@/vibes/soul/sections/wishlist-details'; +import { getSessionCustomerAccessToken } from '~/auth'; import { ExistingResultType } from '~/client/util'; +import type { CurrencyCode } from '~/components/header/fragment'; import { defaultPageInfo, pageInfoTransformer } from '~/data-transformers/page-info-transformer'; import { wishlistDetailsTransformer } from '~/data-transformers/wishlists-transformer'; import { redirect } from '~/i18n/routing'; +import { getPreferredCurrencyCode } from '~/lib/currency'; import { isMobileUser } from '~/lib/user-agent'; import { removeWishlistItem } from '../_actions/remove-wishlist-item'; @@ -39,11 +42,19 @@ async function getWishlist( pt: ExistingResultType>, searchParamsPromise: Promise, locale: string, + customerAccessToken?: string, + currencyCode?: CurrencyCode, ): Promise { const entityId = Number(id); const searchParamsParsed = searchParamsCache.parse(await searchParamsPromise); const formatter = await getFormatter(); - const wishlist = await getCustomerWishlist(entityId, searchParamsParsed); + const wishlist = await getCustomerWishlist( + locale, + entityId, + searchParamsParsed, + customerAccessToken, + currencyCode, + ); if (!wishlist) { return redirect({ href: '/account/wishlists/', locale }); @@ -52,10 +63,22 @@ async function getWishlist( return wishlistDetailsTransformer(wishlist, t, pt, formatter); } -const getAnalyticsData = async (id: string, searchParamsPromise: Promise) => { +const getAnalyticsData = async ( + locale: string, + id: string, + searchParamsPromise: Promise, + customerAccessToken?: string, + currencyCode?: CurrencyCode, +) => { const entityId = Number(id); const searchParamsParsed = searchParamsCache.parse(await searchParamsPromise); - const wishlist = await getCustomerWishlist(entityId, searchParamsParsed); + const wishlist = await getCustomerWishlist( + locale, + entityId, + searchParamsParsed, + customerAccessToken, + currencyCode, + ); if (!wishlist) { return []; @@ -77,12 +100,21 @@ const getAnalyticsData = async (id: string, searchParamsPromise: Promise, + customerAccessToken?: string, + currencyCode?: CurrencyCode, ): Promise { const entityId = Number(id); const searchParamsParsed = searchParamsCache.parse(await searchParamsPromise); - const wishlist = await getCustomerWishlist(entityId, searchParamsParsed); + const wishlist = await getCustomerWishlist( + locale, + entityId, + searchParamsParsed, + customerAccessToken, + currencyCode, + ); return pageInfoTransformer(wishlist?.items.pageInfo ?? defaultPageInfo); } @@ -92,8 +124,12 @@ export default async function WishlistPage({ params, searchParams }: Props) { setRequestLocale(locale); - const t = await getTranslations('Wishlist'); - const pt = await getTranslations('Product.ProductDetails'); + const [t, pt, customerAccessToken, currencyCode] = await Promise.all([ + getTranslations('Wishlist'), + getTranslations('Product.ProductDetails'), + getSessionCustomerAccessToken(), + getPreferredCurrencyCode(), + ]); const wishlistActions = (wishlist?: Wishlist) => { if (!wishlist) { return ; @@ -127,16 +163,24 @@ export default async function WishlistPage({ params, searchParams }: Props) { }; return ( - getAnalyticsData(id, searchParams))}> + + getAnalyticsData(locale, id, searchParams, customerAccessToken, currencyCode), + )} + > getPaginationInfo(id, searchParams))} + paginationInfo={Streamable.from(() => + getPaginationInfo(locale, id, searchParams, customerAccessToken, currencyCode), + )} prevHref="/account/wishlists" removeAction={removeWishlistItem} removeButtonTitle={t('removeButtonTitle')} - wishlist={Streamable.from(() => getWishlist(id, t, pt, searchParams, locale))} + wishlist={Streamable.from(() => + getWishlist(id, t, pt, searchParams, locale, customerAccessToken, currencyCode), + )} /> ); diff --git a/core/app/[locale]/(default)/account/wishlists/page-data.ts b/core/app/[locale]/(default)/account/wishlists/page-data.ts index 02a1c3f7b1..fef85399e0 100644 --- a/core/app/[locale]/(default)/account/wishlists/page-data.ts +++ b/core/app/[locale]/(default)/account/wishlists/page-data.ts @@ -1,11 +1,10 @@ import { cache } from 'react'; -import { getSessionCustomerAccessToken } from '~/auth'; import { client } from '~/client'; import { graphql } from '~/client/graphql'; import { TAGS } from '~/client/tags'; +import type { CurrencyCode } from '~/components/header/fragment'; import { WishlistsFragment } from '~/components/wishlist/fragment'; -import { getPreferredCurrencyCode } from '~/lib/currency'; const WishlistsPageQuery = graphql( ` @@ -33,22 +32,28 @@ interface Pagination { after: string | null; } -export const getCustomerWishlists = cache(async ({ limit = 9, before, after }: Pagination) => { - const customerAccessToken = await getSessionCustomerAccessToken(); - const currencyCode = await getPreferredCurrencyCode(); - const paginationArgs = before ? { last: limit, before } : { first: limit, after }; - const response = await client.fetch({ - document: WishlistsPageQuery, - variables: { ...paginationArgs, currencyCode }, - customerAccessToken, - fetchOptions: { cache: 'no-store', next: { tags: [TAGS.customer] } }, - }); +export const getCustomerWishlists = cache( + async ( + locale: string, + { limit = 9, before, after }: Pagination, + customerAccessToken?: string, + currencyCode?: CurrencyCode, + ) => { + const paginationArgs = before ? { last: limit, before } : { first: limit, after }; + const response = await client.fetch({ + document: WishlistsPageQuery, + variables: { ...paginationArgs, currencyCode }, + locale, + customerAccessToken, + fetchOptions: { cache: 'no-store', next: { tags: [TAGS.customer] } }, + }); - const wishlists = response.data.customer?.wishlists; + const wishlists = response.data.customer?.wishlists; - if (!wishlists) { - return null; - } + if (!wishlists) { + return null; + } - return wishlists; -}); + return wishlists; + }, +); diff --git a/core/app/[locale]/(default)/account/wishlists/page.tsx b/core/app/[locale]/(default)/account/wishlists/page.tsx index 5fba791cfa..26e9b738c0 100644 --- a/core/app/[locale]/(default)/account/wishlists/page.tsx +++ b/core/app/[locale]/(default)/account/wishlists/page.tsx @@ -7,9 +7,12 @@ import { CursorPaginationInfo } from '@/vibes/soul/primitives/cursor-pagination' import * as Skeleton from '@/vibes/soul/primitives/skeleton'; import { Wishlist } from '@/vibes/soul/sections/wishlist-details'; import { WishlistsSection } from '@/vibes/soul/sections/wishlists-section'; +import { getSessionCustomerAccessToken } from '~/auth'; import { ExistingResultType } from '~/client/util'; +import type { CurrencyCode } from '~/components/header/fragment'; import { defaultPageInfo, pageInfoTransformer } from '~/data-transformers/page-info-transformer'; import { wishlistsTransformer } from '~/data-transformers/wishlists-transformer'; +import { getPreferredCurrencyCode } from '~/lib/currency'; import { isMobileUser } from '~/lib/user-agent'; import { NewWishlistButton } from './_components/new-wishlist-button'; @@ -36,12 +39,20 @@ const searchParamsCache = createSearchParamsCache({ }); async function listWishlists( + locale: string, searchParamsPromise: Promise, t: ExistingResultType>, + customerAccessToken?: string, + currencyCode?: CurrencyCode, ): Promise { const searchParamsParsed = searchParamsCache.parse(await searchParamsPromise); const formatter = await getFormatter(); - const wishlists = await getCustomerWishlists(searchParamsParsed); + const wishlists = await getCustomerWishlists( + locale, + searchParamsParsed, + customerAccessToken, + currencyCode, + ); if (!wishlists) { return []; @@ -51,10 +62,18 @@ async function listWishlists( } async function getPaginationInfo( + locale: string, searchParamsPromise: Promise, + customerAccessToken?: string, + currencyCode?: CurrencyCode, ): Promise { const searchParamsParsed = searchParamsCache.parse(await searchParamsPromise); - const wishlists = await getCustomerWishlists(searchParamsParsed); + const wishlists = await getCustomerWishlists( + locale, + searchParamsParsed, + customerAccessToken, + currencyCode, + ); return pageInfoTransformer(wishlists?.pageInfo ?? defaultPageInfo); } @@ -64,8 +83,12 @@ export default async function Wishlists({ params, searchParams }: Props) { setRequestLocale(locale); - const t = await getTranslations('Wishlist'); - const isMobile = await isMobileUser(); + const [t, isMobile, customerAccessToken, currencyCode] = await Promise.all([ + getTranslations('Wishlist'), + isMobileUser(), + getSessionCustomerAccessToken(), + getPreferredCurrencyCode(), + ]); const newWishlistModal = getNewWishlistModal(t); return ( @@ -121,10 +144,14 @@ export default async function Wishlists({ params, searchParams }: Props) { ); }, }} - paginationInfo={Streamable.from(() => getPaginationInfo(searchParams))} + paginationInfo={Streamable.from(() => + getPaginationInfo(locale, searchParams, customerAccessToken, currencyCode), + )} title={t('title')} viewWishlistLabel={t('viewWishlist')} - wishlists={Streamable.from(() => listWishlists(searchParams, t))} + wishlists={Streamable.from(() => + listWishlists(locale, searchParams, t, customerAccessToken, currencyCode), + )} /> ); } diff --git a/core/app/[locale]/(default)/blog/[blogId]/page-data.ts b/core/app/[locale]/(default)/blog/[blogId]/page-data.ts index c1b1213590..3acda342f3 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/page-data.ts +++ b/core/app/[locale]/(default)/blog/[blogId]/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -41,10 +40,11 @@ const BlogPageQuery = graphql(` type Variables = VariablesOf; const getCachedBlogPageData = unstable_cache( - async (_locale: string, variables: Variables) => { + async (locale: string, variables: Variables) => { const response = await client.fetch({ document: BlogPageQuery, variables, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -60,8 +60,6 @@ const getCachedBlogPageData = unstable_cache( { revalidate }, ); -export const getBlogPageData = cache(async (variables: Variables) => { - const locale = await getLocale(); - +export const getBlogPageData = cache(async (locale: string, variables: Variables) => { return getCachedBlogPageData(locale, variables); }); diff --git a/core/app/[locale]/(default)/blog/[blogId]/page.tsx b/core/app/[locale]/(default)/blog/[blogId]/page.tsx index 6b8da45019..49537ac9ef 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/page.tsx +++ b/core/app/[locale]/(default)/blog/[blogId]/page.tsx @@ -23,7 +23,7 @@ export async function generateMetadata({ params }: Props): Promise { const variables = cachedBlogPageDataVariables(blogId); - const blog = await getBlogPageData(variables); + const blog = await getBlogPageData(locale, variables); const blogPost = blog?.post; if (!blogPost) { @@ -45,11 +45,11 @@ export async function generateMetadata({ params }: Props): Promise { async function getBlogPost(props: Props): Promise { const format = await getFormatter(); - const { blogId } = await props.params; + const { blogId, locale } = await props.params; const variables = cachedBlogPageDataVariables(blogId); - const blog = await getBlogPageData(variables); + const blog = await getBlogPageData(locale, variables); const blogPost = blog?.post; if (!blog || !blogPost) { @@ -76,11 +76,11 @@ async function getBlogPost(props: Props): Promise { async function getBlogPostBreadcrumbs(props: Props): Promise { const t = await getTranslations('Blog'); - const { blogId } = await props.params; + const { blogId, locale } = await props.params; const variables = cachedBlogPageDataVariables(blogId); - const blog = await getBlogPageData(variables); + const blog = await getBlogPageData(locale, variables); const blogPost = blog?.post; if (!blog || !blogPost) { diff --git a/core/app/[locale]/(default)/blog/page-data.ts b/core/app/[locale]/(default)/blog/page-data.ts index 575f003f66..bd62608475 100644 --- a/core/app/[locale]/(default)/blog/page-data.ts +++ b/core/app/[locale]/(default)/blog/page-data.ts @@ -1,6 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { unstable_cache } from 'next/cache'; -import { getFormatter, getLocale } from 'next-intl/server'; +import { getFormatter } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -74,10 +74,10 @@ interface Pagination { } const getCachedBlog = unstable_cache( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async (_locale: string) => { + async (locale: string) => { const response = await client.fetch({ document: BlogQuery, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -87,23 +87,19 @@ const getCachedBlog = unstable_cache( { revalidate }, ); -export const getBlog = cache(async () => { - const locale = await getLocale(); - +export const getBlog = cache(async (locale: string) => { return getCachedBlog(locale); }); const getCachedBlogPosts = unstable_cache( - async ( - _locale: string, - { tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination, - ) => { + async (locale: string, { tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination) => { const filterArgs = tag ? { filters: { tags: [tag] } } : {}; const paginationArgs = before ? { last: limit, before } : { first: limit, after }; const response = await client.fetch({ document: BlogPostsPageQuery, variables: { ...filterArgs, ...paginationArgs }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -136,8 +132,7 @@ const getCachedBlogPosts = unstable_cache( ); export const getBlogPosts = cache( - async ({ tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination) => { - const locale = await getLocale(); + async (locale: string, { tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination) => { const raw = await getCachedBlogPosts(locale, { tag, limit, before, after }); if (!raw) { diff --git a/core/app/[locale]/(default)/blog/page.tsx b/core/app/[locale]/(default)/blog/page.tsx index 1b8d90cf91..f7b972f709 100644 --- a/core/app/[locale]/(default)/blog/page.tsx +++ b/core/app/[locale]/(default)/blog/page.tsx @@ -29,7 +29,7 @@ export async function generateMetadata({ params }: Props): Promise { const { locale } = await params; const t = await getTranslations({ locale, namespace: 'Blog' }); - const blog = await getBlog(); + const blog = await getBlog(locale); const description = blog?.description && blog.description.length > 150 @@ -43,9 +43,9 @@ export async function generateMetadata({ params }: Props): Promise { }; } -async function listBlogPosts(searchParamsPromise: Promise) { +async function listBlogPosts(locale: string, searchParamsPromise: Promise) { const searchParamsParsed = searchParamsCache.parse(await searchParamsPromise); - const blogPosts = await getBlogPosts(searchParamsParsed); + const blogPosts = await getBlogPosts(locale, searchParamsParsed); const posts = blogPosts?.posts ?? []; return posts; @@ -63,9 +63,9 @@ async function getEmptyStateSubtitle(): Promise { return t('subtitle'); } -async function getPaginationInfo(searchParamsPromise: Promise) { +async function getPaginationInfo(locale: string, searchParamsPromise: Promise) { const searchParamsParsed = searchParamsCache.parse(await searchParamsPromise); - const blogPosts = await getBlogPosts(searchParamsParsed); + const blogPosts = await getBlogPosts(locale, searchParamsParsed); return pageInfoTransformer(blogPosts?.pageInfo ?? defaultPageInfo); } @@ -79,7 +79,7 @@ export default async function Blog(props: Props) { const searchParamsParsed = searchParamsCache.parse(await props.searchParams); const { tag } = searchParamsParsed; - const blog = await getBlog(); + const blog = await getBlog(locale); if (!blog) { return notFound(); @@ -103,9 +103,9 @@ export default async function Blog(props: Props) { description={blog.description} emptyStateSubtitle={Streamable.from(getEmptyStateSubtitle)} emptyStateTitle={Streamable.from(getEmptyStateTitle)} - paginationInfo={Streamable.from(() => getPaginationInfo(props.searchParams))} + paginationInfo={Streamable.from(() => getPaginationInfo(locale, props.searchParams))} placeholderCount={6} - posts={Streamable.from(() => listBlogPosts(props.searchParams))} + posts={Streamable.from(() => listBlogPosts(locale, props.searchParams))} title={blog.name} /> ); diff --git a/core/app/[locale]/(default)/cart/_actions/update-coupon-code.ts b/core/app/[locale]/(default)/cart/_actions/update-coupon-code.ts index 01611007f7..55ffc640dd 100644 --- a/core/app/[locale]/(default)/cart/_actions/update-coupon-code.ts +++ b/core/app/[locale]/(default)/cart/_actions/update-coupon-code.ts @@ -3,9 +3,10 @@ import { BigCommerceGQLError } from '@bigcommerce/catalyst-client'; import { SubmissionResult } from '@conform-to/react'; import { parseWithZod } from '@conform-to/zod'; -import { getTranslations } from 'next-intl/server'; +import { getLocale, getTranslations } from 'next-intl/server'; import { couponCodeActionFormDataSchema } from '@/vibes/soul/sections/cart/schema'; +import { getSessionCustomerAccessToken } from '~/auth'; import { getCartId } from '~/lib/cart'; import { getCart } from '../page-data'; @@ -34,7 +35,11 @@ export const updateCouponCode = async ( return { ...prevState, lastResult: submission.reply({ formErrors: [t('cartNotFound')] }) }; } - const cart = await getCart({ cartId }); + const [locale, customerAccessToken] = await Promise.all([ + getLocale(), + getSessionCustomerAccessToken(), + ]); + const cart = await getCart(locale, { cartId }, customerAccessToken); const checkout = cart.site.checkout; if (!checkout) { diff --git a/core/app/[locale]/(default)/cart/_actions/update-gift-certificate.ts b/core/app/[locale]/(default)/cart/_actions/update-gift-certificate.ts index b7f2c52ac3..bf1aa88e42 100644 --- a/core/app/[locale]/(default)/cart/_actions/update-gift-certificate.ts +++ b/core/app/[locale]/(default)/cart/_actions/update-gift-certificate.ts @@ -3,9 +3,10 @@ import { BigCommerceGQLError } from '@bigcommerce/catalyst-client'; import { SubmissionResult } from '@conform-to/react'; import { parseWithZod } from '@conform-to/zod'; -import { getTranslations } from 'next-intl/server'; +import { getLocale, getTranslations } from 'next-intl/server'; import { giftCertificateCodeActionFormDataSchema } from '@/vibes/soul/sections/cart/schema'; +import { getSessionCustomerAccessToken } from '~/auth'; import { getCartId } from '~/lib/cart'; import { getCart } from '../page-data'; @@ -36,7 +37,11 @@ export const updateGiftCertificate = async ( return { ...prevState, lastResult: submission.reply({ formErrors: [t('cartNotFound')] }) }; } - const cart = await getCart({ cartId }); + const [locale, customerAccessToken] = await Promise.all([ + getLocale(), + getSessionCustomerAccessToken(), + ]); + const cart = await getCart(locale, { cartId }, customerAccessToken); const checkout = cart.site.checkout; if (!checkout) { diff --git a/core/app/[locale]/(default)/cart/_actions/update-shipping-info.ts b/core/app/[locale]/(default)/cart/_actions/update-shipping-info.ts index 662ba0f7a6..809a3e6d43 100644 --- a/core/app/[locale]/(default)/cart/_actions/update-shipping-info.ts +++ b/core/app/[locale]/(default)/cart/_actions/update-shipping-info.ts @@ -2,10 +2,11 @@ import { BigCommerceGQLError } from '@bigcommerce/catalyst-client'; import { parseWithZod } from '@conform-to/zod'; -import { getTranslations } from 'next-intl/server'; +import { getLocale, getTranslations } from 'next-intl/server'; import { shippingActionFormDataSchema } from '@/vibes/soul/sections/cart/schema'; import { ShippingFormState } from '@/vibes/soul/sections/cart/shipping-form'; +import { getSessionCustomerAccessToken } from '~/auth'; import { getCartId } from '~/lib/cart'; import { getCart } from '../page-data'; @@ -32,7 +33,11 @@ export const updateShippingInfo = async ( return { ...prevState, lastResult: submission.reply({ formErrors: [t('cartNotFound')] }) }; } - const cart = await getCart({ cartId }); + const [locale, customerAccessToken] = await Promise.all([ + getLocale(), + getSessionCustomerAccessToken(), + ]); + const cart = await getCart(locale, { cartId }, customerAccessToken); const checkout = cart.site.checkout; if (!checkout || !cart.site.cart) { diff --git a/core/app/[locale]/(default)/cart/page-data.ts b/core/app/[locale]/(default)/cart/page-data.ts index 62ffc30dff..19d9d58d6f 100644 --- a/core/app/[locale]/(default)/cart/page-data.ts +++ b/core/app/[locale]/(default)/cart/page-data.ts @@ -1,8 +1,6 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; -import { getSessionCustomerAccessToken } from '~/auth'; import { client } from '~/client'; import { graphql, VariablesOf } from '~/client/graphql'; import { revalidate } from '~/client/revalidate-target'; @@ -297,12 +295,15 @@ const CartPageQuery = graphql( type Variables = VariablesOf; -export const getCart = async (variables: Variables) => { - const customerAccessToken = await getSessionCustomerAccessToken(); - +export const getCart = async ( + locale: string, + variables: Variables, + customerAccessToken?: string, +) => { const { data } = await client.fetch({ document: CartPageQuery, variables, + locale, customerAccessToken, fetchOptions: { cache: 'no-store', @@ -339,10 +340,10 @@ const SupportedShippingDestinationsQuery = graphql(` `); const getCachedShippingCountries = unstable_cache( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async (_locale: string) => { + async (locale: string) => { const { data } = await client.fetch({ document: SupportedShippingDestinationsQuery, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -352,8 +353,6 @@ const getCachedShippingCountries = unstable_cache( { revalidate }, ); -export const getShippingCountries = cache(async () => { - const locale = await getLocale(); - +export const getShippingCountries = cache(async (locale: string) => { return getCachedShippingCountries(locale); }); diff --git a/core/app/[locale]/(default)/cart/page.tsx b/core/app/[locale]/(default)/cart/page.tsx index bc07f3d473..9967347516 100644 --- a/core/app/[locale]/(default)/cart/page.tsx +++ b/core/app/[locale]/(default)/cart/page.tsx @@ -4,6 +4,7 @@ import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/serve import { Streamable } from '@/vibes/soul/lib/streamable'; import { Cart as CartComponent, CartEmptyState } from '@/vibes/soul/sections/cart'; import { CartAnalyticsProvider } from '~/app/[locale]/(default)/cart/_components/cart-analytics-provider'; +import { getSessionCustomerAccessToken } from '~/auth'; import { getCartId } from '~/lib/cart'; import { getPreferredCurrencyCode } from '~/lib/currency'; import { exists } from '~/lib/utils'; @@ -32,8 +33,8 @@ export async function generateMetadata({ params }: Props): Promise { }; } -const getAnalyticsData = async (cartId: string) => { - const data = await getCart({ cartId }); +const getAnalyticsData = async (locale: string, cartId: string, customerAccessToken?: string) => { + const data = await getCart(locale, { cartId }, customerAccessToken); const cart = data.site.cart; @@ -65,10 +66,7 @@ export default async function Cart({ params }: Props) { setRequestLocale(locale); - const t = await getTranslations('Cart'); - const tGiftCertificates = await getTranslations('GiftCertificates'); - const format = await getFormatter(); - const cartId = await getCartId(); + const [t, cartId] = await Promise.all([getTranslations('Cart'), getCartId()]); if (!cartId) { return ( @@ -80,8 +78,13 @@ export default async function Cart({ params }: Props) { ); } - const currencyCode = await getPreferredCurrencyCode(); - const data = await getCart({ cartId, currencyCode }); + const [tGiftCertificates, format, currencyCode, customerAccessToken] = await Promise.all([ + getTranslations('GiftCertificates'), + getFormatter(), + getPreferredCurrencyCode(), + getSessionCustomerAccessToken(), + ]); + const data = await getCart(locale, { cartId, currencyCode }, customerAccessToken); const cart = data.site.cart; const checkout = data.site.checkout; @@ -227,7 +230,7 @@ export default async function Cart({ params }: Props) { checkout?.shippingConsignments?.find((consignment) => consignment.selectedShippingOption) || checkout?.shippingConsignments?.[0]; - const shippingCountries = await getShippingCountries(); + const shippingCountries = await getShippingCountries(locale); const countries = shippingCountries.map((country) => ({ value: country.code, @@ -260,7 +263,9 @@ export default async function Cart({ params }: Props) { return ( <> - getAnalyticsData(cartId))}> + getAnalyticsData(locale, cartId, customerAccessToken))} + > {checkoutUrl ? : null} { + async (locale: string, productIds: number[], currencyCode: CurrencyCode | undefined) => { if (productIds.length === 0) { return []; } @@ -70,6 +69,7 @@ const getCachedComparedProducts = unstable_cache( first: productIds.length ? MAX_COMPARE_LIMIT : 0, currencyCode, }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -80,7 +80,12 @@ const getCachedComparedProducts = unstable_cache( ); export const getComparedProducts = cache( - async (productIds: number[] = [], currencyCode?: CurrencyCode, customerAccessToken?: string) => { + async ( + locale: string, + productIds: number[] = [], + currencyCode?: CurrencyCode, + customerAccessToken?: string, + ) => { if (customerAccessToken) { if (productIds.length === 0) { return []; @@ -94,14 +99,13 @@ export const getComparedProducts = cache( currencyCode, }, customerAccessToken, + locale, fetchOptions: { cache: 'no-store' }, }); return removeEdgesAndNodes(data.site.products); } - const locale = await getLocale(); - return getCachedComparedProducts(locale, productIds, currencyCode); }, ); diff --git a/core/app/[locale]/(default)/compare/page.tsx b/core/app/[locale]/(default)/compare/page.tsx index ac851ddb1a..e99acf7944 100644 --- a/core/app/[locale]/(default)/compare/page.tsx +++ b/core/app/[locale]/(default)/compare/page.tsx @@ -64,7 +64,12 @@ export default async function Compare(props: Props) { const parsed = CompareParamsSchema.parse(searchParams); const productIds = parsed.ids?.filter((id) => !Number.isNaN(id)); - const products = await getComparedProducts(productIds, currencyCode, customerAccessToken); + const products = await getComparedProducts( + locale, + productIds, + currencyCode, + customerAccessToken, + ); const format = await getFormatter(); return products.map((product) => ({ @@ -97,7 +102,12 @@ export default async function Compare(props: Props) { const parsed = CompareParamsSchema.parse(searchParams); const productIds = parsed.ids?.filter((id) => !Number.isNaN(id)); - const products = await getComparedProducts(productIds, currencyCode, customerAccessToken); + const products = await getComparedProducts( + locale, + productIds, + currencyCode, + customerAccessToken, + ); return products.map((product) => { return { diff --git a/core/app/[locale]/(default)/gift-certificates/balance/page.tsx b/core/app/[locale]/(default)/gift-certificates/balance/page.tsx index 0320e48acb..e6eca42d97 100644 --- a/core/app/[locale]/(default)/gift-certificates/balance/page.tsx +++ b/core/app/[locale]/(default)/gift-certificates/balance/page.tsx @@ -32,7 +32,7 @@ export default async function GiftCertificates(props: Props) { const t = await getTranslations('GiftCertificates'); const currencyCode = await getPreferredCurrencyCode(); - const data = await getGiftCertificatesData(currencyCode); + const data = await getGiftCertificatesData(locale, currencyCode); if (!data.giftCertificatesEnabled) { return redirect({ href: '/', locale }); diff --git a/core/app/[locale]/(default)/gift-certificates/page-data.ts b/core/app/[locale]/(default)/gift-certificates/page-data.ts index daaf33c0f1..5ece542997 100644 --- a/core/app/[locale]/(default)/gift-certificates/page-data.ts +++ b/core/app/[locale]/(default)/gift-certificates/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -29,10 +28,11 @@ const GiftCertificatesRootQuery = graphql( ); const getCachedGiftCertificatesData = unstable_cache( - async (_locale: string, currencyCode: CurrencyCode | undefined) => { + async (locale: string, currencyCode?: CurrencyCode) => { const response = await client.fetch({ document: GiftCertificatesRootQuery, variables: { currencyCode }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -46,8 +46,8 @@ const getCachedGiftCertificatesData = unstable_cache( { revalidate }, ); -export const getGiftCertificatesData = cache(async (currencyCode?: CurrencyCode) => { - const locale = await getLocale(); - - return getCachedGiftCertificatesData(locale, currencyCode); -}); +export const getGiftCertificatesData = cache( + async (locale: string, currencyCode?: CurrencyCode) => { + return getCachedGiftCertificatesData(locale, currencyCode); + }, +); diff --git a/core/app/[locale]/(default)/gift-certificates/page.tsx b/core/app/[locale]/(default)/gift-certificates/page.tsx index 5c50984fb3..67e62827c0 100644 --- a/core/app/[locale]/(default)/gift-certificates/page.tsx +++ b/core/app/[locale]/(default)/gift-certificates/page.tsx @@ -31,7 +31,7 @@ export default async function GiftCertificates(props: Props) { const t = await getTranslations('GiftCertificates'); const format = await getFormatter(); const currencyCode = await getPreferredCurrencyCode(); - const data = await getGiftCertificatesData(currencyCode); + const data = await getGiftCertificatesData(locale, currencyCode); if (!data.giftCertificatesEnabled) { return redirect({ href: '/', locale }); diff --git a/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts b/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts index ebda9f09a8..76b763f086 100644 --- a/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts +++ b/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -32,10 +31,11 @@ const GiftCertificatePurchaseSettingsQuery = graphql( ); const getCachedGiftCertificatePurchaseData = unstable_cache( - async (_locale: string, currencyCode: CurrencyCode | undefined) => { + async (locale: string, currencyCode?: CurrencyCode) => { const response = await client.fetch({ document: GiftCertificatePurchaseSettingsQuery, variables: { currencyCode }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -50,8 +50,8 @@ const getCachedGiftCertificatePurchaseData = unstable_cache( { revalidate }, ); -export const getGiftCertificatePurchaseData = cache(async (currencyCode?: CurrencyCode) => { - const locale = await getLocale(); - - return getCachedGiftCertificatePurchaseData(locale, currencyCode); -}); +export const getGiftCertificatePurchaseData = cache( + async (locale: string, currencyCode?: CurrencyCode) => { + return getCachedGiftCertificatePurchaseData(locale, currencyCode); + }, +); diff --git a/core/app/[locale]/(default)/gift-certificates/purchase/page.tsx b/core/app/[locale]/(default)/gift-certificates/purchase/page.tsx index 29e4158c75..06d5bdc30e 100644 --- a/core/app/[locale]/(default)/gift-certificates/purchase/page.tsx +++ b/core/app/[locale]/(default)/gift-certificates/purchase/page.tsx @@ -153,7 +153,7 @@ export default async function GiftCertificatePurchasePage({ params }: Props) { const t = await getTranslations({ locale, namespace: 'GiftCertificates' }); const format = await getFormatter(); const currencyCode = await getPreferredCurrencyCode(); - const data = await getGiftCertificatePurchaseData(currencyCode); + const data = await getGiftCertificatePurchaseData(locale, currencyCode); if (!data.giftCertificateSettings?.isEnabled) { return redirect({ href: '/', locale }); diff --git a/core/app/[locale]/(default)/page-data.ts b/core/app/[locale]/(default)/page-data.ts index b3b0b8a353..4f529eeb40 100644 --- a/core/app/[locale]/(default)/page-data.ts +++ b/core/app/[locale]/(default)/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -80,10 +79,11 @@ const HomePageQuery = graphql( ); const getCachedPageData = unstable_cache( - async (_locale: string, currencyCode: CurrencyCode | undefined) => { + async (locale: string, currencyCode: CurrencyCode | undefined) => { const { data } = await client.fetch({ document: HomePageQuery, variables: { currencyCode }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -94,20 +94,19 @@ const getCachedPageData = unstable_cache( ); export const getPageData = cache( - async (currencyCode?: CurrencyCode, customerAccessToken?: string) => { + async (locale: string, currencyCode?: CurrencyCode, customerAccessToken?: string) => { if (customerAccessToken) { const { data } = await client.fetch({ document: HomePageQuery, customerAccessToken, variables: { currencyCode }, + locale, fetchOptions: { cache: 'no-store' }, }); return data; } - const locale = await getLocale(); - return getCachedPageData(locale, currencyCode); }, ); diff --git a/core/app/[locale]/(default)/page.tsx b/core/app/[locale]/(default)/page.tsx index 77cf4db613..ebb7c52655 100644 --- a/core/app/[locale]/(default)/page.tsx +++ b/core/app/[locale]/(default)/page.tsx @@ -38,7 +38,7 @@ export default async function Home({ params }: Props) { const customerAccessToken = await getSessionCustomerAccessToken(); const currencyCode = await getPreferredCurrencyCode(); - return getPageData(currencyCode, customerAccessToken); + return getPageData(locale, currencyCode, customerAccessToken); }); const streamableFeaturedProducts = Streamable.from(async () => { diff --git a/core/app/[locale]/(default)/product/[slug]/page-data.ts b/core/app/[locale]/(default)/product/[slug]/page-data.ts index 9204bbbfd1..ac6d3fcdda 100644 --- a/core/app/[locale]/(default)/product/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/product/[slug]/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -157,10 +156,11 @@ const ProductPageMetadataQuery = graphql(` `); const getCachedProductPageMetadata = unstable_cache( - async (_locale: string, entityId: number) => { + async (locale: string, entityId: number) => { const { data } = await client.fetch({ document: ProductPageMetadataQuery, variables: { entityId }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -171,20 +171,19 @@ const getCachedProductPageMetadata = unstable_cache( ); export const getProductPageMetadata = cache( - async (entityId: number, customerAccessToken?: string) => { + async (locale: string, entityId: number, customerAccessToken?: string) => { if (customerAccessToken) { const { data } = await client.fetch({ document: ProductPageMetadataQuery, variables: { entityId }, customerAccessToken, + locale, fetchOptions: { cache: 'no-store' }, }); return data.site.product; } - const locale = await getLocale(); - return getCachedProductPageMetadata(locale, entityId); }, ); @@ -223,10 +222,11 @@ const ProductQuery = graphql( ); const getCachedProduct = unstable_cache( - async (_locale: string, entityId: number) => { + async (locale: string, entityId: number) => { const { data } = await client.fetch({ document: ProductQuery, variables: { entityId }, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -236,22 +236,23 @@ const getCachedProduct = unstable_cache( { revalidate }, ); -export const getProduct = cache(async (entityId: number, customerAccessToken?: string) => { - if (customerAccessToken) { - const { data } = await client.fetch({ - document: ProductQuery, - variables: { entityId }, - customerAccessToken, - fetchOptions: { cache: 'no-store' }, - }); - - return data.site; - } +export const getProduct = cache( + async (locale: string, entityId: number, customerAccessToken?: string) => { + if (customerAccessToken) { + const { data } = await client.fetch({ + document: ProductQuery, + variables: { entityId }, + customerAccessToken, + locale, + fetchOptions: { cache: 'no-store' }, + }); - const locale = await getLocale(); + return data.site; + } - return getCachedProduct(locale, entityId); -}); + return getCachedProduct(locale, entityId); + }, +); const StreamableProductVariantInventoryBySkuQuery = graphql(` query ProductVariantBySkuQuery($productId: Int!, $sku: String!) { @@ -292,10 +293,11 @@ const StreamableProductVariantInventoryBySkuQuery = graphql(` type VariantInventoryVariables = VariablesOf; const getCachedStreamableProductVariantInventory = unstable_cache( - async (_locale: string, variables: VariantInventoryVariables) => { + async (locale: string, variables: VariantInventoryVariables) => { const { data } = await client.fetch({ document: StreamableProductVariantInventoryBySkuQuery, variables, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -306,20 +308,19 @@ const getCachedStreamableProductVariantInventory = unstable_cache( ); export const getStreamableProductVariantInventory = cache( - async (variables: VariantInventoryVariables, customerAccessToken?: string) => { + async (locale: string, variables: VariantInventoryVariables, customerAccessToken?: string) => { if (customerAccessToken) { const { data } = await client.fetch({ document: StreamableProductVariantInventoryBySkuQuery, variables, customerAccessToken, + locale, fetchOptions: { cache: 'no-store' }, }); return data.site.product?.variants; } - const locale = await getLocale(); - return getCachedStreamableProductVariantInventory(locale, variables); }, ); @@ -385,10 +386,11 @@ const StreamableProductQuery = graphql( type Variables = VariablesOf; const getCachedStreamableProduct = unstable_cache( - async (_locale: string, variables: Variables) => { + async (locale: string, variables: Variables) => { const { data } = await client.fetch({ document: StreamableProductQuery, variables, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -399,20 +401,19 @@ const getCachedStreamableProduct = unstable_cache( ); export const getStreamableProduct = cache( - async (variables: Variables, customerAccessToken?: string) => { + async (locale: string, variables: Variables, customerAccessToken?: string) => { if (customerAccessToken) { const { data } = await client.fetch({ document: StreamableProductQuery, variables, customerAccessToken, + locale, fetchOptions: { cache: 'no-store' }, }); return data.site.product; } - const locale = await getLocale(); - return getCachedStreamableProduct(locale, variables); }, ); @@ -448,10 +449,11 @@ const StreamableProductInventoryQuery = graphql( type ProductInventoryVariables = VariablesOf; const getCachedStreamableProductInventory = unstable_cache( - async (_locale: string, variables: ProductInventoryVariables) => { + async (locale: string, variables: ProductInventoryVariables) => { const { data } = await client.fetch({ document: StreamableProductInventoryQuery, variables, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -462,20 +464,19 @@ const getCachedStreamableProductInventory = unstable_cache( ); export const getStreamableProductInventory = cache( - async (variables: ProductInventoryVariables, customerAccessToken?: string) => { + async (locale: string, variables: ProductInventoryVariables, customerAccessToken?: string) => { if (customerAccessToken) { const { data } = await client.fetch({ document: StreamableProductInventoryQuery, variables, customerAccessToken, + locale, fetchOptions: { cache: 'no-store' }, }); return data.site.product; } - const locale = await getLocale(); - return getCachedStreamableProductInventory(locale, variables); }, ); @@ -512,10 +513,11 @@ const ProductPricingAndRelatedProductsQuery = graphql( ); const getCachedProductPricingAndRelatedProducts = unstable_cache( - async (_locale: string, variables: Variables) => { + async (locale: string, variables: Variables) => { const { data } = await client.fetch({ document: ProductPricingAndRelatedProductsQuery, variables, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -526,20 +528,19 @@ const getCachedProductPricingAndRelatedProducts = unstable_cache( ); export const getProductPricingAndRelatedProducts = cache( - async (variables: Variables, customerAccessToken?: string) => { + async (locale: string, variables: Variables, customerAccessToken?: string) => { if (customerAccessToken) { const { data } = await client.fetch({ document: ProductPricingAndRelatedProductsQuery, variables, customerAccessToken, + locale, fetchOptions: { cache: 'no-store' }, }); return data.site.product; } - const locale = await getLocale(); - return getCachedProductPricingAndRelatedProducts(locale, variables); }, ); @@ -563,10 +564,10 @@ const InventorySettingsQuery = graphql(` `); const getCachedStreamableInventorySettingsQuery = unstable_cache( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async (_locale: string) => { + async (locale: string) => { const { data } = await client.fetch({ document: InventorySettingsQuery, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -576,18 +577,19 @@ const getCachedStreamableInventorySettingsQuery = unstable_cache( { revalidate }, ); -export const getStreamableInventorySettingsQuery = cache(async (customerAccessToken?: string) => { - if (customerAccessToken) { - const { data } = await client.fetch({ - document: InventorySettingsQuery, - customerAccessToken, - fetchOptions: { cache: 'no-store' }, - }); - - return data.site.settings?.inventory; - } +export const getStreamableInventorySettingsQuery = cache( + async (locale: string, customerAccessToken?: string) => { + if (customerAccessToken) { + const { data } = await client.fetch({ + document: InventorySettingsQuery, + customerAccessToken, + locale, + fetchOptions: { cache: 'no-store' }, + }); - const locale = await getLocale(); + return data.site.settings?.inventory; + } - return getCachedStreamableInventorySettingsQuery(locale); -}); + return getCachedStreamableInventorySettingsQuery(locale); + }, +); diff --git a/core/app/[locale]/(default)/product/[slug]/page.tsx b/core/app/[locale]/(default)/product/[slug]/page.tsx index c1e8a96bf7..07d1f446e1 100644 --- a/core/app/[locale]/(default)/product/[slug]/page.tsx +++ b/core/app/[locale]/(default)/product/[slug]/page.tsx @@ -44,7 +44,7 @@ export async function generateMetadata({ params }: Props): Promise { const productId = Number(slug); - const product = await getProductPageMetadata(productId, customerAccessToken); + const product = await getProductPageMetadata(locale, productId, customerAccessToken); if (!product) { return notFound(); @@ -76,7 +76,11 @@ export default async function Product({ params, searchParams }: Props) { const productId = Number(slug); - const { product: baseProduct, settings } = await getProduct(productId, customerAccessToken); + const { product: baseProduct, settings } = await getProduct( + locale, + productId, + customerAccessToken, + ); const reviewsEnabled = Boolean(settings?.reviews.enabled && !settings.display.showProductRating); const showRating = Boolean(settings?.reviews.enabled && settings.display.showProductRating); @@ -103,7 +107,7 @@ export default async function Product({ params, searchParams }: Props) { useDefaultOptionSelections: true, }; - const product = await getStreamableProduct(variables, customerAccessToken); + const product = await getStreamableProduct(locale, variables, customerAccessToken); if (!product) { return notFound(); @@ -119,7 +123,7 @@ export default async function Product({ params, searchParams }: Props) { entityId: Number(productId), }; - const product = await getStreamableProductInventory(variables, customerAccessToken); + const product = await getStreamableProductInventory(locale, variables, customerAccessToken); if (!product) { return notFound(); @@ -140,7 +144,11 @@ export default async function Product({ params, searchParams }: Props) { sku: product.sku, }; - const variants = await getStreamableProductVariantInventory(variables, customerAccessToken); + const variants = await getStreamableProductVariantInventory( + locale, + variables, + customerAccessToken, + ); if (!variants) { return undefined; @@ -170,7 +178,7 @@ export default async function Product({ params, searchParams }: Props) { currencyCode, }; - return await getProductPricingAndRelatedProducts(variables, customerAccessToken); + return await getProductPricingAndRelatedProducts(locale, variables, customerAccessToken); }); const streamablePrices = Streamable.from(async () => { @@ -238,7 +246,7 @@ export default async function Product({ params, searchParams }: Props) { }); const streamableInventorySettings = Streamable.from(async () => { - return await getStreamableInventorySettingsQuery(customerAccessToken); + return await getStreamableInventorySettingsQuery(locale, customerAccessToken); }); const getBackorderAvailabilityPrompt = ({ 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 dbabff46f1..c1952ca187 100644 --- a/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -34,10 +33,11 @@ const ContactPageQuery = graphql( type Variables = VariablesOf; const getCachedWebpageData = unstable_cache( - async (_locale: string, variables: Variables) => { + async (locale: string, variables: Variables) => { const { data } = await client.fetch({ document: ContactPageQuery, variables, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -47,8 +47,6 @@ const getCachedWebpageData = unstable_cache( { revalidate }, ); -export const getWebpageData = cache(async (variables: Variables) => { - const locale = await getLocale(); - +export const getWebpageData = cache(async (locale: string, variables: Variables) => { return getCachedWebpageData(locale, variables); }); diff --git a/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx b/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx index b8d1f2e759..291068b27c 100644 --- a/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx +++ b/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx @@ -40,8 +40,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 (locale: string, id: string): Promise => { + const data = await getWebpageData(locale, { id: decodeURIComponent(id) }); const webpage = data.node?.__typename === 'ContactPage' ? data.node : null; if (!webpage) { @@ -61,10 +61,10 @@ const getWebPage = cache(async (id: string): Promise => { }; }); -async function getWebPageBreadcrumbs(id: string): Promise { +async function getWebPageBreadcrumbs(locale: string, id: string): Promise { const t = await getTranslations('WebPages.ContactUs'); - const webpage = await getWebPage(id); + const webpage = await getWebPage(locale, id); const [, ...rest] = webpage.breadcrumbs.reverse(); const breadcrumbs = [ { @@ -81,8 +81,8 @@ 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(locale: string, id: string, message: string) { + const webpage = await getWebPage(locale, id); return { ...webpage, @@ -90,9 +90,9 @@ async function getWebPageWithSuccessContent(id: string, message: string) { }; } -async function getContactFields(id: string) { +async function getContactFields(locale: string, id: string) { const t = await getTranslations('WebPages.ContactUs.Form'); - const { entityId, path, contactFields } = await getWebPage(id); + const { entityId, path, contactFields } = await getWebPage(locale, id); const toGroupsOfTwo = (fields: Field[]) => fields.reduce>>((acc, _, i) => { if (i % 2 === 0) { @@ -155,7 +155,7 @@ async function getContactFields(id: string) { export async function generateMetadata({ params }: Props): Promise { const { id, locale } = await params; - const webpage = await getWebPage(id); + const webpage = await getWebPage(locale, id); const { pageTitle, metaDescription, metaKeywords } = webpage.seo; return { @@ -179,8 +179,8 @@ 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(locale, id))} + webPage={Streamable.from(() => getWebPageWithSuccessContent(locale, id, t('success')))} > getWebPageBreadcrumbs(id))} - webPage={Streamable.from(() => getWebPage(id))} + breadcrumbs={Streamable.from(() => getWebPageBreadcrumbs(locale, id))} + webPage={Streamable.from(() => getWebPage(locale, id))} >
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 ea924b35a9..1a6bc521f1 100644 --- a/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -32,10 +31,11 @@ const NormalPageQuery = graphql( type Variables = VariablesOf; const getCachedWebpageData = unstable_cache( - async (_locale: string, variables: Variables) => { + async (locale: string, variables: Variables) => { const { data } = await client.fetch({ document: NormalPageQuery, variables, + locale, fetchOptions: { cache: 'no-store' }, }); @@ -45,8 +45,6 @@ const getCachedWebpageData = unstable_cache( { revalidate }, ); -export const getWebpageData = cache(async (variables: Variables) => { - const locale = await getLocale(); - +export const getWebpageData = cache(async (locale: string, variables: Variables) => { return getCachedWebpageData(locale, variables); }); diff --git a/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx b/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx index a222ea18c8..3b55299d9e 100644 --- a/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx +++ b/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx @@ -19,8 +19,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 (locale: string, id: string): Promise => { + const data = await getWebpageData(locale, { id: decodeURIComponent(id) }); const webpage = data.node?.__typename === 'NormalPage' ? data.node : null; if (!webpage) { @@ -37,10 +37,10 @@ const getWebPage = cache(async (id: string): Promise => { }; }); -async function getWebPageBreadcrumbs(id: string): Promise { +async function getWebPageBreadcrumbs(locale: string, id: string): Promise { const t = await getTranslations('WebPages.Normal'); - const webpage = await getWebPage(id); + const webpage = await getWebPage(locale, id); const [, ...rest] = webpage.breadcrumbs.reverse(); const breadcrumbs = [ { @@ -59,7 +59,7 @@ async function getWebPageBreadcrumbs(id: string): Promise { export async function generateMetadata({ params }: Props): Promise { const { id, locale } = await params; - const webpage = await getWebPage(id); + const webpage = await getWebPage(locale, id); const { pageTitle, metaDescription, metaKeywords } = webpage.seo; // Get the path from the last breadcrumb @@ -80,8 +80,8 @@ export default async function WebPage({ params }: Props) { return ( getWebPageBreadcrumbs(id))} - webPage={Streamable.from(() => getWebPage(id))} + breadcrumbs={Streamable.from(() => getWebPageBreadcrumbs(locale, id))} + webPage={Streamable.from(() => getWebPage(locale, id))} /> ); } diff --git a/core/app/[locale]/(default)/wishlist/[token]/page-data.ts b/core/app/[locale]/(default)/wishlist/[token]/page-data.ts index 51acdc92ba..d03424ea59 100644 --- a/core/app/[locale]/(default)/wishlist/[token]/page-data.ts +++ b/core/app/[locale]/(default)/wishlist/[token]/page-data.ts @@ -1,5 +1,4 @@ import { unstable_cache } from 'next/cache'; -import { getLocale } from 'next-intl/server'; import { cache } from 'react'; import { client } from '~/client'; @@ -7,9 +6,9 @@ import { PaginationFragment } from '~/client/fragments/pagination'; import { graphql } from '~/client/graphql'; import { revalidate } from '~/client/revalidate-target'; import { TAGS } from '~/client/tags'; +import type { CurrencyCode } from '~/components/header/fragment'; import { ProductCardFragment } from '~/components/product-card/fragment'; import { WishlistItemFragment } from '~/components/wishlist/fragment'; -import { getPreferredCurrencyCode } from '~/lib/currency'; const PublicWishlistQuery = graphql( ` @@ -53,35 +52,26 @@ interface Pagination { } const getCachedPublicWishlist = unstable_cache( - async ( - _locale: string, - token: string, - pagination: Pagination, - currencyCode: string | undefined, - ) => { + async (locale: string, token: string, pagination: Pagination, currencyCode?: CurrencyCode) => { const { before, after, limit = 9 } = pagination; const paginationArgs = before ? { last: limit, before } : { first: limit, after }; const response = await client.fetch({ document: PublicWishlistQuery, variables: { ...paginationArgs, currencyCode, token }, + locale, fetchOptions: { cache: 'no-store' }, }); const wishlist = response.data.site.publicWishlist; - if (!wishlist) { - return null; - } - return wishlist; }, ['get-public-wishlist'], { revalidate, tags: [TAGS.customer] }, ); -export const getPublicWishlist = cache(async (token: string, pagination: Pagination) => { - const currencyCode = await getPreferredCurrencyCode(); - const locale = await getLocale(); - - return getCachedPublicWishlist(locale, token, pagination, currencyCode); -}); +export const getPublicWishlist = cache( + async (locale: string, token: string, pagination: Pagination, currencyCode?: CurrencyCode) => { + return getCachedPublicWishlist(locale, token, pagination, currencyCode); + }, +); diff --git a/core/app/[locale]/(default)/wishlist/[token]/page.tsx b/core/app/[locale]/(default)/wishlist/[token]/page.tsx index e6fe52378f..ab4d7bcc50 100644 --- a/core/app/[locale]/(default)/wishlist/[token]/page.tsx +++ b/core/app/[locale]/(default)/wishlist/[token]/page.tsx @@ -13,12 +13,14 @@ import { Wishlist, WishlistDetails } from '@/vibes/soul/sections/wishlist-detail import { addWishlistItemToCart } from '~/app/[locale]/(default)/account/wishlists/[id]/_actions/add-to-cart'; import { WishlistAnalyticsProvider } from '~/app/[locale]/(default)/account/wishlists/[id]/_components/wishlist-analytics-provider'; import { ExistingResultType } from '~/client/util'; +import type { CurrencyCode } from '~/components/header/fragment'; import { WishlistShareButton, WishlistShareButtonSkeleton, } from '~/components/wishlist/share-button'; import { defaultPageInfo, pageInfoTransformer } from '~/data-transformers/page-info-transformer'; import { publicWishlistDetailsTransformer } from '~/data-transformers/wishlists-transformer'; +import { getPreferredCurrencyCode } from '~/lib/currency'; import { getMetadataAlternates } from '~/lib/seo/canonical'; import { isMobileUser } from '~/lib/user-agent'; @@ -38,14 +40,16 @@ const searchParamsCache = createSearchParamsCache({ }); async function getWishlist( + locale: string, token: string, t: ExistingResultType>, pt: ExistingResultType>, searchParams: Promise, + currencyCode: CurrencyCode | undefined, ): Promise { const searchParamsParsed = searchParamsCache.parse(await searchParams); const formatter = await getFormatter(); - const wishlist = await getPublicWishlist(token, searchParamsParsed); + const wishlist = await getPublicWishlist(locale, token, searchParamsParsed, currencyCode); if (!wishlist) { return notFound(); @@ -55,11 +59,13 @@ async function getWishlist( } async function getPaginationInfo( + locale: string, token: string, searchParams: Promise, + currencyCode: CurrencyCode | undefined, ): Promise { const searchParamsParsed = searchParamsCache.parse(await searchParams); - const wishlist = await getPublicWishlist(token, searchParamsParsed); + const wishlist = await getPublicWishlist(locale, token, searchParamsParsed, currencyCode); return pageInfoTransformer(wishlist?.items.pageInfo ?? defaultPageInfo); } @@ -70,7 +76,8 @@ export async function generateMetadata({ params, searchParams }: Props): Promise // to make sure we aren't bypassing an existing cache just for the metadata generation. const searchParamsParsed = searchParamsCache.parse(await searchParams); const t = await getTranslations({ locale, namespace: 'PublicWishlist' }); - const wishlist = await getPublicWishlist(token, searchParamsParsed); + const currencyCode = await getPreferredCurrencyCode(); + const wishlist = await getPublicWishlist(locale, token, searchParamsParsed, currencyCode); return { title: wishlist?.name ?? t('title'), @@ -78,9 +85,14 @@ export async function generateMetadata({ params, searchParams }: Props): Promise }; } -const getAnalyticsData = async (token: string, searchParamsPromise: Promise) => { +const getAnalyticsData = async ( + locale: string, + token: string, + searchParamsPromise: Promise, + currencyCode: CurrencyCode | undefined, +) => { const searchParamsParsed = searchParamsCache.parse(await searchParamsPromise); - const wishlist = await getPublicWishlist(token, searchParamsParsed); + const wishlist = await getPublicWishlist(locale, token, searchParamsParsed, currencyCode); if (!wishlist) { return []; @@ -102,12 +114,14 @@ const getAnalyticsData = async (token: string, searchParamsPromise: Promise, + currencyCode: CurrencyCode | undefined, ): Promise { const t = await getTranslations('PublicWishlist'); const searchParamsParsed = searchParamsCache.parse(await searchParams); - const wishlist = await getPublicWishlist(token, searchParamsParsed); + const wishlist = await getPublicWishlist(locale, token, searchParamsParsed, currencyCode); return [ { href: '/', label: 'Home' }, @@ -120,6 +134,7 @@ export default async function PublicWishlist({ params, searchParams }: Props) { setRequestLocale(locale); + const currencyCode = await getPreferredCurrencyCode(); const t = await getTranslations('Wishlist'); const pwt = await getTranslations('PublicWishlist'); const pt = await getTranslations('Product.ProductDetails'); @@ -159,17 +174,27 @@ export default async function PublicWishlist({ params, searchParams }: Props) { }; return ( - getAnalyticsData(token, searchParams))}> + getAnalyticsData(locale, token, searchParams, currencyCode))} + > - getBreadcrumbs(token, searchParams))} /> + + getBreadcrumbs(locale, token, searchParams, currencyCode), + )} + /> getPaginationInfo(token, searchParams))} - wishlist={Streamable.from(() => getWishlist(token, t, pt, searchParams))} + paginationInfo={Streamable.from(() => + getPaginationInfo(locale, token, searchParams, currencyCode), + )} + wishlist={Streamable.from(() => + getWishlist(locale, token, t, pt, searchParams, currencyCode), + )} /> diff --git a/core/client/index.ts b/core/client/index.ts index cb5c73976c..b153aea4ab 100644 --- a/core/client/index.ts +++ b/core/client/index.ts @@ -15,25 +15,6 @@ import { backendUserAgent } from '../user-agent'; // below absorbs this gracefully, and getChannelId falls back to defaultChannelId. import { getCorrelationId } from './correlation-id'; -const getLocale = async () => { - try { - const { getLocale: getServerLocale } = await import('next-intl/server'); - - return await getServerLocale(); - } catch { - /** - * Next-intl `getLocale` only works on the server, and when middleware has run. - * - * Instances when `getLocale` will not work: - * - Requests during next.config.ts resolution - * - Requests in middlewares - * - Requests in `generateStaticParams` - * - Request in api routes - * - Requests in static sites without `setRequestLocale` - */ - } -}; - export const client = createClient({ storefrontToken: process.env.BIGCOMMERCE_STOREFRONT_TOKEN ?? '', storeHash: process.env.BIGCOMMERCE_STORE_HASH ?? '', @@ -42,16 +23,12 @@ export const client = createClient({ logger: (process.env.NODE_ENV !== 'production' && process.env.CLIENT_LOGGER !== 'false') || process.env.CLIENT_LOGGER === 'true', - getChannelId: async (defaultChannelId: string) => { - const locale = await getLocale(); - - // We use the default channelId as a fallback, but it is not ideal in some scenarios. + getChannelId: (defaultChannelId: string, locale?: string) => { return getChannelIdFromLocale(locale) ?? defaultChannelId; }, beforeRequest: async (fetchOptions) => { // We can't serialize a `Headers` object within this method so we have to opt into using a plain object const requestHeaders: Record = {}; - const locale = await getLocale(); if (fetchOptions?.cache && ['no-store', 'no-cache'].includes(fetchOptions.cache)) { const { headers } = await import('next/headers'); @@ -63,10 +40,6 @@ export const client = createClient({ } } - if (locale) { - requestHeaders['Accept-Language'] = locale; - } - requestHeaders['X-Correlation-ID'] = getCorrelationId(); return { diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index dd25618110..6930069969 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -20,7 +20,7 @@ interface Config { platform?: string; backendUserAgentExtensions?: string; logger?: boolean; - getChannelId?: (defaultChannelId: string) => Promise | string; + getChannelId?: (defaultChannelId: string, locale?: string) => Promise | string; beforeRequest?: ( fetchOptions?: FetcherRequestInit, ) => Promise | undefined> | Partial | undefined; @@ -49,7 +49,7 @@ type GraphQLErrorPolicy = 'none' | 'all' | 'auth' | 'ignore'; class Client { private backendUserAgent: string; private readonly defaultChannelId: string; - private getChannelId: (defaultChannelId: string) => Promise | string; + private getChannelId: (defaultChannelId: string, locale?: string) => Promise | string; private beforeRequest?: ( fetchOptions?: FetcherRequestInit, ) => Promise | undefined> | Partial | undefined; @@ -85,6 +85,7 @@ class Client { customerAccessToken?: string; fetchOptions?: FetcherRequestInit; channelId?: string; + locale?: string; errorPolicy?: GraphQLErrorPolicy; validateCustomerAccessToken?: boolean; }): Promise>; @@ -96,6 +97,7 @@ class Client { customerAccessToken?: string; fetchOptions?: FetcherRequestInit; channelId?: string; + locale?: string; errorPolicy?: GraphQLErrorPolicy; validateCustomerAccessToken?: boolean; }): Promise>; @@ -106,6 +108,7 @@ class Client { customerAccessToken, fetchOptions = {} as FetcherRequestInit, channelId, + locale, errorPolicy = 'none', validateCustomerAccessToken = true, }: { @@ -114,6 +117,7 @@ class Client { customerAccessToken?: string; fetchOptions?: FetcherRequestInit; channelId?: string; + locale?: string; errorPolicy?: GraphQLErrorPolicy; validateCustomerAccessToken?: boolean; }): Promise> { @@ -126,6 +130,7 @@ class Client { channelId, operationInfo.name, operationInfo.type, + locale, ); const { headers: additionalFetchHeaders = {}, ...additionalFetchOptions } = (await this.beforeRequest?.(fetchOptions)) ?? {}; @@ -136,6 +141,7 @@ class Client { 'Content-Type': 'application/json', Authorization: `Bearer ${this.config.storefrontToken}`, 'User-Agent': this.backendUserAgent, + ...(locale && { 'Accept-Language': locale }), ...(customerAccessToken && { 'X-Bc-Customer-Access-Token': customerAccessToken }), ...(validateCustomerAccessToken && { 'X-Bc-Error-On-Invalid-Customer-Access-Token': 'true', @@ -210,8 +216,8 @@ class Client { return response.text(); } - private async getCanonicalUrl(channelId?: string) { - const resolvedChannelId = channelId ?? (await this.getChannelId(this.defaultChannelId)); + private async getCanonicalUrl(channelId?: string, locale?: string) { + const resolvedChannelId = channelId ?? (await this.getChannelId(this.defaultChannelId, locale)); return `https://store-${this.config.storeHash}-${resolvedChannelId}.${graphqlApiDomain}`; } @@ -220,8 +226,9 @@ class Client { channelId?: string, operationName?: string, operationType?: string, + locale?: string, ) { - const baseUrl = new URL(`${await this.getCanonicalUrl(channelId)}/graphql`); + const baseUrl = new URL(`${await this.getCanonicalUrl(channelId, locale)}/graphql`); if (operationName) { baseUrl.searchParams.set('operation', operationName); From b30cc4c076ebcb338da875ff35c8982ad6761681 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 13:55:07 -0600 Subject: [PATCH 09/24] fix: remove no-cache --- core/app/[locale]/(default)/(auth)/register/page-data.ts | 1 - .../[locale]/(default)/(faceted)/brand/[slug]/page-data.ts | 1 - .../(default)/(faceted)/category/[slug]/page-data.ts | 1 - .../[locale]/(default)/(faceted)/fetch-compare-products.ts | 1 - .../[locale]/(default)/(faceted)/fetch-faceted-search.ts | 1 - core/app/[locale]/(default)/(faceted)/search/page-data.ts | 1 - core/app/[locale]/(default)/blog/[blogId]/page-data.ts | 1 - core/app/[locale]/(default)/blog/page-data.ts | 2 -- core/app/[locale]/(default)/cart/page-data.ts | 1 - core/app/[locale]/(default)/compare/page-data.ts | 1 - core/app/[locale]/(default)/gift-certificates/page-data.ts | 1 - .../(default)/gift-certificates/purchase/page-data.ts | 1 - core/app/[locale]/(default)/page-data.ts | 1 - core/app/[locale]/(default)/product/[slug]/page-data.ts | 7 ------- .../[locale]/(default)/webpages/[id]/contact/page-data.ts | 1 - .../[locale]/(default)/webpages/[id]/normal/page-data.ts | 1 - core/app/[locale]/(default)/wishlist/[token]/page-data.ts | 1 - 17 files changed, 24 deletions(-) diff --git a/core/app/[locale]/(default)/(auth)/register/page-data.ts b/core/app/[locale]/(default)/(auth)/register/page-data.ts index 7e15fb00fc..d217a5440b 100644 --- a/core/app/[locale]/(default)/(auth)/register/page-data.ts +++ b/core/app/[locale]/(default)/(auth)/register/page-data.ts @@ -72,7 +72,6 @@ const getCachedRegisterCustomerQuery = unstable_cache( customerFilters: customer?.filters, customerSortBy: customer?.sortBy, }, - fetchOptions: { cache: 'no-store' }, locale, }); diff --git a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts index c7e0296921..0f16edef20 100644 --- a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts @@ -45,7 +45,6 @@ const getCachedBrandPageData = unstable_cache( document: BrandPageQuery, variables: { entityId }, locale, - fetchOptions: { cache: 'no-store' }, }); return response.data.site; diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts index 2e49f085d5..a233ac3d85 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts @@ -65,7 +65,6 @@ const getCachedCategoryPageData = unstable_cache( document: CategoryPageQuery, variables: { entityId }, locale, - fetchOptions: { cache: 'no-store' }, }); return response.data.site; diff --git a/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts b/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts index af4f0139ce..95ff718aef 100644 --- a/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts +++ b/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts @@ -55,7 +55,6 @@ const getCachedCompareProducts = unstable_cache( document: CompareProductsQuery, variables: { ...parsedVariables, first: MAX_COMPARE_LIMIT }, locale, - fetchOptions: { cache: 'no-store' }, }); return removeEdgesAndNodes(response.data.site.products); diff --git a/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts b/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts index 6c230abdc7..5dfa6b6bf7 100644 --- a/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts +++ b/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts @@ -192,7 +192,6 @@ const getCachedProductSearchResults = unstable_cache( document: GetProductSearchResultsQuery, variables: { ...filterArgs, ...paginationArgs, currencyCode }, locale, - fetchOptions: { cache: 'no-store' }, }); const { site } = response.data; diff --git a/core/app/[locale]/(default)/(faceted)/search/page-data.ts b/core/app/[locale]/(default)/(faceted)/search/page-data.ts index 607832f973..540b29ff1e 100644 --- a/core/app/[locale]/(default)/(faceted)/search/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/search/page-data.ts @@ -35,7 +35,6 @@ const getCachedSearchPageData = unstable_cache( const response = await client.fetch({ document: SearchPageQuery, locale, - fetchOptions: { cache: 'no-store' }, }); return response.data.site; diff --git a/core/app/[locale]/(default)/blog/[blogId]/page-data.ts b/core/app/[locale]/(default)/blog/[blogId]/page-data.ts index 3acda342f3..f2f56fae16 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/page-data.ts +++ b/core/app/[locale]/(default)/blog/[blogId]/page-data.ts @@ -45,7 +45,6 @@ const getCachedBlogPageData = unstable_cache( document: BlogPageQuery, variables, locale, - fetchOptions: { cache: 'no-store' }, }); const { blog } = response.data.site.content; diff --git a/core/app/[locale]/(default)/blog/page-data.ts b/core/app/[locale]/(default)/blog/page-data.ts index bd62608475..3c5268d594 100644 --- a/core/app/[locale]/(default)/blog/page-data.ts +++ b/core/app/[locale]/(default)/blog/page-data.ts @@ -78,7 +78,6 @@ const getCachedBlog = unstable_cache( const response = await client.fetch({ document: BlogQuery, locale, - fetchOptions: { cache: 'no-store' }, }); return response.data.site.content.blog; @@ -100,7 +99,6 @@ const getCachedBlogPosts = unstable_cache( document: BlogPostsPageQuery, variables: { ...filterArgs, ...paginationArgs }, locale, - fetchOptions: { cache: 'no-store' }, }); const { blog } = response.data.site.content; diff --git a/core/app/[locale]/(default)/cart/page-data.ts b/core/app/[locale]/(default)/cart/page-data.ts index 19d9d58d6f..4074dbcaf4 100644 --- a/core/app/[locale]/(default)/cart/page-data.ts +++ b/core/app/[locale]/(default)/cart/page-data.ts @@ -344,7 +344,6 @@ const getCachedShippingCountries = unstable_cache( const { data } = await client.fetch({ document: SupportedShippingDestinationsQuery, locale, - fetchOptions: { cache: 'no-store' }, }); return data.site.settings?.shipping?.supportedShippingDestinations.countries ?? []; diff --git a/core/app/[locale]/(default)/compare/page-data.ts b/core/app/[locale]/(default)/compare/page-data.ts index 430deb0f5d..3f4a2031d6 100644 --- a/core/app/[locale]/(default)/compare/page-data.ts +++ b/core/app/[locale]/(default)/compare/page-data.ts @@ -70,7 +70,6 @@ const getCachedComparedProducts = unstable_cache( currencyCode, }, locale, - fetchOptions: { cache: 'no-store' }, }); return removeEdgesAndNodes(data.site.products); diff --git a/core/app/[locale]/(default)/gift-certificates/page-data.ts b/core/app/[locale]/(default)/gift-certificates/page-data.ts index 5ece542997..4a429d8d58 100644 --- a/core/app/[locale]/(default)/gift-certificates/page-data.ts +++ b/core/app/[locale]/(default)/gift-certificates/page-data.ts @@ -33,7 +33,6 @@ const getCachedGiftCertificatesData = unstable_cache( document: GiftCertificatesRootQuery, variables: { currencyCode }, locale, - fetchOptions: { cache: 'no-store' }, }); return { diff --git a/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts b/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts index 76b763f086..aefec121ba 100644 --- a/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts +++ b/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts @@ -36,7 +36,6 @@ const getCachedGiftCertificatePurchaseData = unstable_cache( document: GiftCertificatePurchaseSettingsQuery, variables: { currencyCode }, locale, - fetchOptions: { cache: 'no-store' }, }); return { diff --git a/core/app/[locale]/(default)/page-data.ts b/core/app/[locale]/(default)/page-data.ts index 4f529eeb40..47e0e6eb27 100644 --- a/core/app/[locale]/(default)/page-data.ts +++ b/core/app/[locale]/(default)/page-data.ts @@ -84,7 +84,6 @@ const getCachedPageData = unstable_cache( document: HomePageQuery, variables: { currencyCode }, locale, - fetchOptions: { cache: 'no-store' }, }); return data; diff --git a/core/app/[locale]/(default)/product/[slug]/page-data.ts b/core/app/[locale]/(default)/product/[slug]/page-data.ts index ac6d3fcdda..178e94271f 100644 --- a/core/app/[locale]/(default)/product/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/product/[slug]/page-data.ts @@ -161,7 +161,6 @@ const getCachedProductPageMetadata = unstable_cache( document: ProductPageMetadataQuery, variables: { entityId }, locale, - fetchOptions: { cache: 'no-store' }, }); return data.site.product; @@ -227,7 +226,6 @@ const getCachedProduct = unstable_cache( document: ProductQuery, variables: { entityId }, locale, - fetchOptions: { cache: 'no-store' }, }); return data.site; @@ -298,7 +296,6 @@ const getCachedStreamableProductVariantInventory = unstable_cache( document: StreamableProductVariantInventoryBySkuQuery, variables, locale, - fetchOptions: { cache: 'no-store' }, }); return data.site.product?.variants; @@ -391,7 +388,6 @@ const getCachedStreamableProduct = unstable_cache( document: StreamableProductQuery, variables, locale, - fetchOptions: { cache: 'no-store' }, }); return data.site.product; @@ -454,7 +450,6 @@ const getCachedStreamableProductInventory = unstable_cache( document: StreamableProductInventoryQuery, variables, locale, - fetchOptions: { cache: 'no-store' }, }); return data.site.product; @@ -518,7 +513,6 @@ const getCachedProductPricingAndRelatedProducts = unstable_cache( document: ProductPricingAndRelatedProductsQuery, variables, locale, - fetchOptions: { cache: 'no-store' }, }); return data.site.product; @@ -568,7 +562,6 @@ const getCachedStreamableInventorySettingsQuery = unstable_cache( const { data } = await client.fetch({ document: InventorySettingsQuery, locale, - fetchOptions: { cache: 'no-store' }, }); return data.site.settings?.inventory; 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 c1952ca187..13e6bf84b6 100644 --- a/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts @@ -38,7 +38,6 @@ const getCachedWebpageData = unstable_cache( document: ContactPageQuery, variables, locale, - fetchOptions: { cache: 'no-store' }, }); return data; 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 1a6bc521f1..bfe84c1670 100644 --- a/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts @@ -36,7 +36,6 @@ const getCachedWebpageData = unstable_cache( document: NormalPageQuery, variables, locale, - fetchOptions: { cache: 'no-store' }, }); return data; diff --git a/core/app/[locale]/(default)/wishlist/[token]/page-data.ts b/core/app/[locale]/(default)/wishlist/[token]/page-data.ts index d03424ea59..a000318bb1 100644 --- a/core/app/[locale]/(default)/wishlist/[token]/page-data.ts +++ b/core/app/[locale]/(default)/wishlist/[token]/page-data.ts @@ -59,7 +59,6 @@ const getCachedPublicWishlist = unstable_cache( document: PublicWishlistQuery, variables: { ...paginationArgs, currencyCode, token }, locale, - fetchOptions: { cache: 'no-store' }, }); const wishlist = response.data.site.publicWishlist; From 12a6dfdf691135750ec883427b8945f5d04d1d31 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 14:33:04 -0600 Subject: [PATCH 10/24] feat: enable cache components --- .../(auth)/change-password/page-data.ts | 36 ++-- .../(default)/(auth)/register/page-data.ts | 62 +++---- .../(faceted)/brand/[slug]/page-data.ts | 26 +-- .../(faceted)/category/[slug]/page-data.ts | 26 +-- .../(faceted)/fetch-compare-products.ts | 34 ++-- .../(faceted)/fetch-faceted-search.ts | 132 ++++++------- .../(default)/(faceted)/search/page-data.ts | 24 +-- .../(default)/blog/[blogId]/page-data.ts | 34 ++-- core/app/[locale]/(default)/blog/page-data.ts | 95 +++++----- core/app/[locale]/(default)/cart/page-data.ts | 24 +-- .../[locale]/(default)/compare/page-data.ts | 44 +++-- .../(default)/gift-certificates/page-data.ts | 34 ++-- .../gift-certificates/purchase/page-data.ts | 38 ++-- core/app/[locale]/(default)/page-data.ts | 26 +-- .../(default)/product/[slug]/page-data.ts | 174 +++++++++--------- .../webpages/[id]/contact/page-data.ts | 28 +-- .../webpages/[id]/normal/page-data.ts | 28 +-- .../(default)/wishlist/[token]/page-data.ts | 38 ++-- core/app/[locale]/layout.tsx | 2 - core/app/favicon.ico/route.ts | 2 - core/app/robots.txt/route.ts | 2 - core/next.config.ts | 1 + 22 files changed, 462 insertions(+), 448 deletions(-) diff --git a/core/app/[locale]/(default)/(auth)/change-password/page-data.ts b/core/app/[locale]/(default)/(auth)/change-password/page-data.ts index c48ab1d1a4..e6b1f6ed83 100644 --- a/core/app/[locale]/(default)/(auth)/change-password/page-data.ts +++ b/core/app/[locale]/(default)/(auth)/change-password/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -25,23 +25,23 @@ const ChangePasswordQuery = graphql(` } `); -const getCachedChangePasswordQuery = unstable_cache( - async (locale: string) => { - const response = await client.fetch({ - document: ChangePasswordQuery, - locale, - }); - - const passwordComplexitySettings = - response.data.site.settings?.customers?.passwordComplexitySettings; - - return { - passwordComplexitySettings, - }; - }, - ['get-change-password-query'], - { revalidate }, -); +async function getCachedChangePasswordQuery(locale: string) { + 'use cache'; + + cacheLife({ revalidate }); + + const response = await client.fetch({ + document: ChangePasswordQuery, + locale, + }); + + const passwordComplexitySettings = + response.data.site.settings?.customers?.passwordComplexitySettings; + + return { + passwordComplexitySettings, + }; +} export const getChangePasswordQuery = cache(async (locale: string) => { return getCachedChangePasswordQuery(locale); diff --git a/core/app/[locale]/(default)/(auth)/register/page-data.ts b/core/app/[locale]/(default)/(auth)/register/page-data.ts index d217a5440b..59f09b61c0 100644 --- a/core/app/[locale]/(default)/(auth)/register/page-data.ts +++ b/core/app/[locale]/(default)/(auth)/register/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -62,39 +62,39 @@ interface Props { }; } -const getCachedRegisterCustomerQuery = unstable_cache( - async (locale: string, { address, customer }: Props) => { - const response = await client.fetch({ - document: RegisterCustomerQuery, - variables: { - addressFilters: address?.filters, - addressSortBy: address?.sortBy, - customerFilters: customer?.filters, - customerSortBy: customer?.sortBy, - }, - locale, - }); +async function getCachedRegisterCustomerQuery(locale: string, { address, customer }: Props) { + 'use cache'; - const addressFields = response.data.site.settings?.formFields.shippingAddress; - const customerFields = response.data.site.settings?.formFields.customer; - const countries = response.data.geography.countries; - const passwordComplexitySettings = - response.data.site.settings?.customers?.passwordComplexitySettings; + cacheLife({ revalidate }); - if (!addressFields || !customerFields) { - return null; - } + const response = await client.fetch({ + document: RegisterCustomerQuery, + variables: { + addressFilters: address?.filters, + addressSortBy: address?.sortBy, + customerFilters: customer?.filters, + customerSortBy: customer?.sortBy, + }, + locale, + }); - return { - addressFields, - customerFields, - countries, - passwordComplexitySettings, - }; - }, - ['get-register-customer-query'], - { revalidate }, -); + const addressFields = response.data.site.settings?.formFields.shippingAddress; + const customerFields = response.data.site.settings?.formFields.customer; + const countries = response.data.geography.countries; + const passwordComplexitySettings = + response.data.site.settings?.customers?.passwordComplexitySettings; + + if (!addressFields || !customerFields) { + return null; + } + + return { + addressFields, + customerFields, + countries, + passwordComplexitySettings, + }; +} export const getRegisterCustomerQuery = cache(async (locale: string, props: Props) => { return getCachedRegisterCustomerQuery(locale, props); diff --git a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts index 0f16edef20..7d3b92817c 100644 --- a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -39,19 +39,19 @@ const BrandPageQuery = graphql(` } `); -const getCachedBrandPageData = unstable_cache( - async (locale: string, entityId: number) => { - const response = await client.fetch({ - document: BrandPageQuery, - variables: { entityId }, - locale, - }); +async function getCachedBrandPageData(locale: string, entityId: number) { + 'use cache'; - return response.data.site; - }, - ['get-brand-page-data'], - { revalidate }, -); + cacheLife({ revalidate }); + + const response = await client.fetch({ + document: BrandPageQuery, + variables: { entityId }, + locale, + }); + + return response.data.site; +} export const getBrandPageData = cache( async (locale: string, entityId: number, customerAccessToken?: string) => { diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts index a233ac3d85..fa56def54f 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -59,19 +59,19 @@ const CategoryPageQuery = graphql( [BreadcrumbsCategoryFragment], ); -const getCachedCategoryPageData = unstable_cache( - async (locale: string, entityId: number) => { - const response = await client.fetch({ - document: CategoryPageQuery, - variables: { entityId }, - locale, - }); +async function getCachedCategoryPageData(locale: string, entityId: number) { + 'use cache'; - return response.data.site; - }, - ['get-category-page-data'], - { revalidate }, -); + cacheLife({ revalidate }); + + const response = await client.fetch({ + document: CategoryPageQuery, + variables: { entityId }, + locale, + }); + + return response.data.site; +} export const getCategoryPageData = cache( async (locale: string, entityId: number, customerAccessToken?: string) => { diff --git a/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts b/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts index 95ff718aef..e54bc447f1 100644 --- a/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts +++ b/core/app/[locale]/(default)/(faceted)/fetch-compare-products.ts @@ -1,6 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { VariablesOf } from 'gql.tada'; -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { z } from 'zod'; @@ -43,25 +43,25 @@ const CompareProductsQuery = graphql(` type Variables = VariablesOf; -const getCachedCompareProducts = unstable_cache( - async (locale: string, variables: Variables) => { - const parsedVariables = CompareProductsSchema.parse(variables); +async function getCachedCompareProducts(locale: string, variables: Variables) { + 'use cache'; - if (parsedVariables.entityIds.length === 0) { - return []; - } + cacheLife({ revalidate }); - const response = await client.fetch({ - document: CompareProductsQuery, - variables: { ...parsedVariables, first: MAX_COMPARE_LIMIT }, - locale, - }); + const parsedVariables = CompareProductsSchema.parse(variables); - return removeEdgesAndNodes(response.data.site.products); - }, - ['get-compare-products'], - { revalidate }, -); + if (parsedVariables.entityIds.length === 0) { + return []; + } + + const response = await client.fetch({ + document: CompareProductsQuery, + variables: { ...parsedVariables, first: MAX_COMPARE_LIMIT }, + locale, + }); + + return removeEdgesAndNodes(response.data.site.products); +} export const getCompareProducts = cache( async (locale: string, variables: Variables, customerAccessToken?: string) => { diff --git a/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts b/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts index 5dfa6b6bf7..793cc5adb3 100644 --- a/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts +++ b/core/app/[locale]/(default)/(faceted)/fetch-faceted-search.ts @@ -1,5 +1,5 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { z } from 'zod'; @@ -179,71 +179,71 @@ interface ProductSearch { filters: SearchProductsFiltersInput; } -const getCachedProductSearchResults = unstable_cache( - async ( - locale: string, - { limit = 9, after, before, sort, filters }: ProductSearch, - currencyCode: CurrencyCode | undefined, - ) => { - const filterArgs = { filters, sort }; - const paginationArgs = before ? { last: limit, before } : { first: limit, after }; - - const response = await client.fetch({ - document: GetProductSearchResultsQuery, - variables: { ...filterArgs, ...paginationArgs, currencyCode }, - locale, - }); - - const { site } = response.data; - const searchResults = site.search.searchProducts; - - const items = removeEdgesAndNodes(searchResults.products).map((product) => ({ - ...product, - })); - - return { - facets: { - items: removeEdgesAndNodes(searchResults.filters).map((node) => { - switch (node.__typename) { - case 'BrandSearchFilter': - return { - ...node, - brands: removeEdgesAndNodes(node.brands), - }; - - case 'CategorySearchFilter': - return { - ...node, - categories: removeEdgesAndNodes(node.categories), - }; - - case 'ProductAttributeSearchFilter': - return { - ...node, - attributes: removeEdgesAndNodes(node.attributes), - }; - - case 'RatingSearchFilter': - return { - ...node, - ratings: removeEdgesAndNodes(node.ratings), - }; - - default: - return node; - } - }), - }, - products: { - collectionInfo: searchResults.products.collectionInfo, - pageInfo: searchResults.products.pageInfo, - items, - }, - }; - }, - ['get-product-search-results'], - { revalidate: 300 }, -); +async function getCachedProductSearchResults( + locale: string, + { limit = 9, after, before, sort, filters }: ProductSearch, + currencyCode: CurrencyCode | undefined, +) { + 'use cache'; + + cacheLife({ revalidate: 300 }); + + const filterArgs = { filters, sort }; + const paginationArgs = before ? { last: limit, before } : { first: limit, after }; + + const response = await client.fetch({ + document: GetProductSearchResultsQuery, + variables: { ...filterArgs, ...paginationArgs, currencyCode }, + locale, + }); + + const { site } = response.data; + const searchResults = site.search.searchProducts; + + const items = removeEdgesAndNodes(searchResults.products).map((product) => ({ + ...product, + })); + + return { + facets: { + items: removeEdgesAndNodes(searchResults.filters).map((node) => { + switch (node.__typename) { + case 'BrandSearchFilter': + return { + ...node, + brands: removeEdgesAndNodes(node.brands), + }; + + case 'CategorySearchFilter': + return { + ...node, + categories: removeEdgesAndNodes(node.categories), + }; + + case 'ProductAttributeSearchFilter': + return { + ...node, + attributes: removeEdgesAndNodes(node.attributes), + }; + + case 'RatingSearchFilter': + return { + ...node, + ratings: removeEdgesAndNodes(node.ratings), + }; + + default: + return node; + } + }), + }, + products: { + collectionInfo: searchResults.products.collectionInfo, + pageInfo: searchResults.products.pageInfo, + items, + }, + }; +} const getProductSearchResults = cache( // We need to make sure the reference passed into this function is the same if we want it to be memoized. diff --git a/core/app/[locale]/(default)/(faceted)/search/page-data.ts b/core/app/[locale]/(default)/(faceted)/search/page-data.ts index 540b29ff1e..4fd9ca8f8a 100644 --- a/core/app/[locale]/(default)/(faceted)/search/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/search/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -30,18 +30,18 @@ const SearchPageQuery = graphql(` } `); -const getCachedSearchPageData = unstable_cache( - async (locale: string) => { - const response = await client.fetch({ - document: SearchPageQuery, - locale, - }); +async function getCachedSearchPageData(locale: string) { + 'use cache'; - return response.data.site; - }, - ['get-search-page-data'], - { revalidate }, -); + cacheLife({ revalidate }); + + const response = await client.fetch({ + document: SearchPageQuery, + locale, + }); + + return response.data.site; +} export const getSearchPageData = cache(async (locale: string) => { return getCachedSearchPageData(locale); diff --git a/core/app/[locale]/(default)/blog/[blogId]/page-data.ts b/core/app/[locale]/(default)/blog/[blogId]/page-data.ts index f2f56fae16..1643f5c1b2 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/page-data.ts +++ b/core/app/[locale]/(default)/blog/[blogId]/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -39,25 +39,25 @@ const BlogPageQuery = graphql(` type Variables = VariablesOf; -const getCachedBlogPageData = unstable_cache( - async (locale: string, variables: Variables) => { - const response = await client.fetch({ - document: BlogPageQuery, - variables, - locale, - }); +async function getCachedBlogPageData(locale: string, variables: Variables) { + 'use cache'; - const { blog } = response.data.site.content; + cacheLife({ revalidate }); - if (!blog?.post) { - return null; - } + const response = await client.fetch({ + document: BlogPageQuery, + variables, + locale, + }); + + const { blog } = response.data.site.content; + + if (!blog?.post) { + return null; + } - return blog; - }, - ['get-blog-page-data'], - { revalidate }, -); + return blog; +} export const getBlogPageData = cache(async (locale: string, variables: Variables) => { return getCachedBlogPageData(locale, variables); diff --git a/core/app/[locale]/(default)/blog/page-data.ts b/core/app/[locale]/(default)/blog/page-data.ts index 3c5268d594..6fc29e0a6d 100644 --- a/core/app/[locale]/(default)/blog/page-data.ts +++ b/core/app/[locale]/(default)/blog/page-data.ts @@ -1,5 +1,5 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { getFormatter } from 'next-intl/server'; import { cache } from 'react'; @@ -73,61 +73,64 @@ interface Pagination { after: string | null; } -const getCachedBlog = unstable_cache( - async (locale: string) => { - const response = await client.fetch({ - document: BlogQuery, - locale, - }); +async function getCachedBlog(locale: string) { + 'use cache'; - return response.data.site.content.blog; - }, - ['get-blog'], - { revalidate }, -); + cacheLife({ revalidate }); + + const response = await client.fetch({ + document: BlogQuery, + locale, + }); + + return response.data.site.content.blog; +} export const getBlog = cache(async (locale: string) => { return getCachedBlog(locale); }); -const getCachedBlogPosts = unstable_cache( - async (locale: string, { tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination) => { - const filterArgs = tag ? { filters: { tags: [tag] } } : {}; - const paginationArgs = before ? { last: limit, before } : { first: limit, after }; +async function getCachedBlogPosts( + locale: string, + { tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination, +) { + 'use cache'; - const response = await client.fetch({ - document: BlogPostsPageQuery, - variables: { ...filterArgs, ...paginationArgs }, - locale, - }); + cacheLife({ revalidate }); - const { blog } = response.data.site.content; + const filterArgs = tag ? { filters: { tags: [tag] } } : {}; + const paginationArgs = before ? { last: limit, before } : { first: limit, after }; - if (!blog) { - return null; - } + const response = await client.fetch({ + document: BlogPostsPageQuery, + variables: { ...filterArgs, ...paginationArgs }, + locale, + }); - return { - pageInfo: blog.posts.pageInfo, - posts: removeEdgesAndNodes(blog.posts).map((post) => ({ - id: String(post.entityId), - author: post.author, - content: post.plainTextSummary, - dateUtc: post.publishedDate.utc, - image: post.thumbnailImage - ? { - src: post.thumbnailImage.url, - alt: post.thumbnailImage.altText, - } - : undefined, - href: post.path, - title: post.name, - })), - }; - }, - ['get-blog-posts'], - { revalidate }, -); + const { blog } = response.data.site.content; + + if (!blog) { + return null; + } + + return { + pageInfo: blog.posts.pageInfo, + posts: removeEdgesAndNodes(blog.posts).map((post) => ({ + id: String(post.entityId), + author: post.author, + content: post.plainTextSummary, + dateUtc: post.publishedDate.utc, + image: post.thumbnailImage + ? { + src: post.thumbnailImage.url, + alt: post.thumbnailImage.altText, + } + : undefined, + href: post.path, + title: post.name, + })), + }; +} export const getBlogPosts = cache( async (locale: string, { tag, limit = 9, before, after }: BlogPostsFiltersInput & Pagination) => { diff --git a/core/app/[locale]/(default)/cart/page-data.ts b/core/app/[locale]/(default)/cart/page-data.ts index 4074dbcaf4..8792940db4 100644 --- a/core/app/[locale]/(default)/cart/page-data.ts +++ b/core/app/[locale]/(default)/cart/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -339,18 +339,18 @@ const SupportedShippingDestinationsQuery = graphql(` } `); -const getCachedShippingCountries = unstable_cache( - async (locale: string) => { - const { data } = await client.fetch({ - document: SupportedShippingDestinationsQuery, - locale, - }); +async function getCachedShippingCountries(locale: string) { + 'use cache'; - return data.site.settings?.shipping?.supportedShippingDestinations.countries ?? []; - }, - ['get-shipping-countries'], - { revalidate }, -); + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: SupportedShippingDestinationsQuery, + locale, + }); + + return data.site.settings?.shipping?.supportedShippingDestinations.countries ?? []; +} export const getShippingCountries = cache(async (locale: string) => { return getCachedShippingCountries(locale); diff --git a/core/app/[locale]/(default)/compare/page-data.ts b/core/app/[locale]/(default)/compare/page-data.ts index 3f4a2031d6..c7c046d9b3 100644 --- a/core/app/[locale]/(default)/compare/page-data.ts +++ b/core/app/[locale]/(default)/compare/page-data.ts @@ -1,5 +1,5 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -56,27 +56,31 @@ const ComparedProductsQuery = graphql( [ProductCardFragment], ); -const getCachedComparedProducts = unstable_cache( - async (locale: string, productIds: number[], currencyCode: CurrencyCode | undefined) => { - if (productIds.length === 0) { - return []; - } +async function getCachedComparedProducts( + locale: string, + productIds: number[], + currencyCode: CurrencyCode | undefined, +) { + 'use cache'; - const { data } = await client.fetch({ - document: ComparedProductsQuery, - variables: { - entityIds: productIds, - first: productIds.length ? MAX_COMPARE_LIMIT : 0, - currencyCode, - }, - locale, - }); + cacheLife({ revalidate }); - return removeEdgesAndNodes(data.site.products); - }, - ['get-compared-products'], - { revalidate }, -); + if (productIds.length === 0) { + return []; + } + + const { data } = await client.fetch({ + document: ComparedProductsQuery, + variables: { + entityIds: productIds, + first: productIds.length ? MAX_COMPARE_LIMIT : 0, + currencyCode, + }, + locale, + }); + + return removeEdgesAndNodes(data.site.products); +} export const getComparedProducts = cache( async ( diff --git a/core/app/[locale]/(default)/gift-certificates/page-data.ts b/core/app/[locale]/(default)/gift-certificates/page-data.ts index 4a429d8d58..0c287b532d 100644 --- a/core/app/[locale]/(default)/gift-certificates/page-data.ts +++ b/core/app/[locale]/(default)/gift-certificates/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -27,23 +27,23 @@ const GiftCertificatesRootQuery = graphql( [StoreLogoFragment], ); -const getCachedGiftCertificatesData = unstable_cache( - async (locale: string, currencyCode?: CurrencyCode) => { - const response = await client.fetch({ - document: GiftCertificatesRootQuery, - variables: { currencyCode }, - locale, - }); +async function getCachedGiftCertificatesData(locale: string, currencyCode?: CurrencyCode) { + 'use cache'; - return { - giftCertificatesEnabled: response.data.site.settings?.giftCertificates?.isEnabled ?? false, - defaultCurrency: response.data.site.settings?.currency.defaultCurrency ?? undefined, - logo: response.data.site.settings ? logoTransformer(response.data.site.settings) : '', - }; - }, - ['get-gift-certificates-data'], - { revalidate }, -); + cacheLife({ revalidate }); + + const response = await client.fetch({ + document: GiftCertificatesRootQuery, + variables: { currencyCode }, + locale, + }); + + return { + giftCertificatesEnabled: response.data.site.settings?.giftCertificates?.isEnabled ?? false, + defaultCurrency: response.data.site.settings?.currency.defaultCurrency ?? undefined, + logo: response.data.site.settings ? logoTransformer(response.data.site.settings) : '', + }; +} export const getGiftCertificatesData = cache( async (locale: string, currencyCode?: CurrencyCode) => { diff --git a/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts b/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts index aefec121ba..e9156f6fc2 100644 --- a/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts +++ b/core/app/[locale]/(default)/gift-certificates/purchase/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -30,24 +30,24 @@ const GiftCertificatePurchaseSettingsQuery = graphql( [GiftCertificateSettingsFragment, StoreLogoFragment], ); -const getCachedGiftCertificatePurchaseData = unstable_cache( - async (locale: string, currencyCode?: CurrencyCode) => { - const response = await client.fetch({ - document: GiftCertificatePurchaseSettingsQuery, - variables: { currencyCode }, - locale, - }); - - return { - giftCertificateSettings: response.data.site.settings?.giftCertificates ?? null, - logo: response.data.site.settings ? logoTransformer(response.data.site.settings) : '', - storeName: response.data.site.settings?.storeName ?? undefined, - defaultCurrency: response.data.site.settings?.currency.defaultCurrency ?? undefined, - }; - }, - ['get-gift-certificate-purchase-data'], - { revalidate }, -); +async function getCachedGiftCertificatePurchaseData(locale: string, currencyCode?: CurrencyCode) { + 'use cache'; + + cacheLife({ revalidate }); + + const response = await client.fetch({ + document: GiftCertificatePurchaseSettingsQuery, + variables: { currencyCode }, + locale, + }); + + return { + giftCertificateSettings: response.data.site.settings?.giftCertificates ?? null, + logo: response.data.site.settings ? logoTransformer(response.data.site.settings) : '', + storeName: response.data.site.settings?.storeName ?? undefined, + defaultCurrency: response.data.site.settings?.currency.defaultCurrency ?? undefined, + }; +} export const getGiftCertificatePurchaseData = cache( async (locale: string, currencyCode?: CurrencyCode) => { diff --git a/core/app/[locale]/(default)/page-data.ts b/core/app/[locale]/(default)/page-data.ts index 47e0e6eb27..7b49ed832f 100644 --- a/core/app/[locale]/(default)/page-data.ts +++ b/core/app/[locale]/(default)/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -78,19 +78,19 @@ const HomePageQuery = graphql( [FeaturedProductsCarouselFragment, FeaturedProductsListFragment], ); -const getCachedPageData = unstable_cache( - async (locale: string, currencyCode: CurrencyCode | undefined) => { - const { data } = await client.fetch({ - document: HomePageQuery, - variables: { currencyCode }, - locale, - }); +async function getCachedPageData(locale: string, currencyCode: CurrencyCode | undefined) { + 'use cache'; - return data; - }, - ['get-page-data'], - { revalidate }, -); + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: HomePageQuery, + variables: { currencyCode }, + locale, + }); + + return data; +} export const getPageData = cache( async (locale: string, currencyCode?: CurrencyCode, customerAccessToken?: string) => { diff --git a/core/app/[locale]/(default)/product/[slug]/page-data.ts b/core/app/[locale]/(default)/product/[slug]/page-data.ts index 178e94271f..b58bc72766 100644 --- a/core/app/[locale]/(default)/product/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/product/[slug]/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -155,19 +155,19 @@ const ProductPageMetadataQuery = graphql(` } `); -const getCachedProductPageMetadata = unstable_cache( - async (locale: string, entityId: number) => { - const { data } = await client.fetch({ - document: ProductPageMetadataQuery, - variables: { entityId }, - locale, - }); +async function getCachedProductPageMetadata(locale: string, entityId: number) { + 'use cache'; - return data.site.product; - }, - ['get-product-page-metadata'], - { revalidate }, -); + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: ProductPageMetadataQuery, + variables: { entityId }, + locale, + }); + + return data.site.product; +} export const getProductPageMetadata = cache( async (locale: string, entityId: number, customerAccessToken?: string) => { @@ -220,19 +220,19 @@ const ProductQuery = graphql( [ProductOptionsFragment], ); -const getCachedProduct = unstable_cache( - async (locale: string, entityId: number) => { - const { data } = await client.fetch({ - document: ProductQuery, - variables: { entityId }, - locale, - }); +async function getCachedProduct(locale: string, entityId: number) { + 'use cache'; - return data.site; - }, - ['get-product'], - { revalidate }, -); + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: ProductQuery, + variables: { entityId }, + locale, + }); + + return data.site; +} export const getProduct = cache( async (locale: string, entityId: number, customerAccessToken?: string) => { @@ -290,19 +290,22 @@ const StreamableProductVariantInventoryBySkuQuery = graphql(` type VariantInventoryVariables = VariablesOf; -const getCachedStreamableProductVariantInventory = unstable_cache( - async (locale: string, variables: VariantInventoryVariables) => { - const { data } = await client.fetch({ - document: StreamableProductVariantInventoryBySkuQuery, - variables, - locale, - }); +async function getCachedStreamableProductVariantInventory( + locale: string, + variables: VariantInventoryVariables, +) { + 'use cache'; - return data.site.product?.variants; - }, - ['get-streamable-product-variant-inventory'], - { revalidate: 60 }, -); + cacheLife({ revalidate: 60 }); + + const { data } = await client.fetch({ + document: StreamableProductVariantInventoryBySkuQuery, + variables, + locale, + }); + + return data.site.product?.variants; +} export const getStreamableProductVariantInventory = cache( async (locale: string, variables: VariantInventoryVariables, customerAccessToken?: string) => { @@ -382,19 +385,19 @@ const StreamableProductQuery = graphql( type Variables = VariablesOf; -const getCachedStreamableProduct = unstable_cache( - async (locale: string, variables: Variables) => { - const { data } = await client.fetch({ - document: StreamableProductQuery, - variables, - locale, - }); +async function getCachedStreamableProduct(locale: string, variables: Variables) { + 'use cache'; - return data.site.product; - }, - ['get-streamable-product'], - { revalidate }, -); + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: StreamableProductQuery, + variables, + locale, + }); + + return data.site.product; +} export const getStreamableProduct = cache( async (locale: string, variables: Variables, customerAccessToken?: string) => { @@ -444,19 +447,22 @@ const StreamableProductInventoryQuery = graphql( type ProductInventoryVariables = VariablesOf; -const getCachedStreamableProductInventory = unstable_cache( - async (locale: string, variables: ProductInventoryVariables) => { - const { data } = await client.fetch({ - document: StreamableProductInventoryQuery, - variables, - locale, - }); +async function getCachedStreamableProductInventory( + locale: string, + variables: ProductInventoryVariables, +) { + 'use cache'; - return data.site.product; - }, - ['get-streamable-product-inventory'], - { revalidate: 60 }, -); + cacheLife({ revalidate: 60 }); + + const { data } = await client.fetch({ + document: StreamableProductInventoryQuery, + variables, + locale, + }); + + return data.site.product; +} export const getStreamableProductInventory = cache( async (locale: string, variables: ProductInventoryVariables, customerAccessToken?: string) => { @@ -507,19 +513,19 @@ const ProductPricingAndRelatedProductsQuery = graphql( [PricingFragment, FeaturedProductsCarouselFragment], ); -const getCachedProductPricingAndRelatedProducts = unstable_cache( - async (locale: string, variables: Variables) => { - const { data } = await client.fetch({ - document: ProductPricingAndRelatedProductsQuery, - variables, - locale, - }); +async function getCachedProductPricingAndRelatedProducts(locale: string, variables: Variables) { + 'use cache'; - return data.site.product; - }, - ['get-product-pricing-and-related-products'], - { revalidate }, -); + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: ProductPricingAndRelatedProductsQuery, + variables, + locale, + }); + + return data.site.product; +} export const getProductPricingAndRelatedProducts = cache( async (locale: string, variables: Variables, customerAccessToken?: string) => { @@ -557,18 +563,18 @@ const InventorySettingsQuery = graphql(` } `); -const getCachedStreamableInventorySettingsQuery = unstable_cache( - async (locale: string) => { - const { data } = await client.fetch({ - document: InventorySettingsQuery, - locale, - }); +async function getCachedStreamableInventorySettingsQuery(locale: string) { + 'use cache'; - return data.site.settings?.inventory; - }, - ['get-streamable-inventory-settings'], - { revalidate }, -); + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: InventorySettingsQuery, + locale, + }); + + return data.site.settings?.inventory; +} export const getStreamableInventorySettingsQuery = cache( async (locale: string, customerAccessToken?: string) => { 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 13e6bf84b6..381b1aa093 100644 --- a/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/contact/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -32,19 +32,19 @@ const ContactPageQuery = graphql( type Variables = VariablesOf; -const getCachedWebpageData = unstable_cache( - async (locale: string, variables: Variables) => { - const { data } = await client.fetch({ - document: ContactPageQuery, - variables, - locale, - }); - - return data; - }, - ['get-contact-webpage-data'], - { revalidate }, -); +async function getCachedWebpageData(locale: string, variables: Variables) { + 'use cache'; + + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: ContactPageQuery, + variables, + locale, + }); + + return data; +} export const getWebpageData = cache(async (locale: string, variables: Variables) => { return getCachedWebpageData(locale, variables); 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 bfe84c1670..c6a8497edc 100644 --- a/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts +++ b/core/app/[locale]/(default)/webpages/[id]/normal/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -30,19 +30,19 @@ const NormalPageQuery = graphql( type Variables = VariablesOf; -const getCachedWebpageData = unstable_cache( - async (locale: string, variables: Variables) => { - const { data } = await client.fetch({ - document: NormalPageQuery, - variables, - locale, - }); - - return data; - }, - ['get-normal-webpage-data'], - { revalidate }, -); +async function getCachedWebpageData(locale: string, variables: Variables) { + 'use cache'; + + cacheLife({ revalidate }); + + const { data } = await client.fetch({ + document: NormalPageQuery, + variables, + locale, + }); + + return data; +} export const getWebpageData = cache(async (locale: string, variables: Variables) => { return getCachedWebpageData(locale, variables); diff --git a/core/app/[locale]/(default)/wishlist/[token]/page-data.ts b/core/app/[locale]/(default)/wishlist/[token]/page-data.ts index a000318bb1..6ebac275e3 100644 --- a/core/app/[locale]/(default)/wishlist/[token]/page-data.ts +++ b/core/app/[locale]/(default)/wishlist/[token]/page-data.ts @@ -1,4 +1,4 @@ -import { unstable_cache } from 'next/cache'; +import { cacheLife, cacheTag } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -51,23 +51,29 @@ interface Pagination { after?: string | null; } -const getCachedPublicWishlist = unstable_cache( - async (locale: string, token: string, pagination: Pagination, currencyCode?: CurrencyCode) => { - const { before, after, limit = 9 } = pagination; - const paginationArgs = before ? { last: limit, before } : { first: limit, after }; - const response = await client.fetch({ - document: PublicWishlistQuery, - variables: { ...paginationArgs, currencyCode, token }, - locale, - }); +async function getCachedPublicWishlist( + locale: string, + token: string, + pagination: Pagination, + currencyCode?: CurrencyCode, +) { + 'use cache'; - const wishlist = response.data.site.publicWishlist; + cacheLife({ revalidate }); + cacheTag(TAGS.customer); - return wishlist; - }, - ['get-public-wishlist'], - { revalidate, tags: [TAGS.customer] }, -); + const { before, after, limit = 9 } = pagination; + const paginationArgs = before ? { last: limit, before } : { first: limit, after }; + const response = await client.fetch({ + document: PublicWishlistQuery, + variables: { ...paginationArgs, currencyCode, token }, + locale, + }); + + const wishlist = response.data.site.publicWishlist; + + return wishlist; +} export const getPublicWishlist = cache( async (locale: string, token: string, pagination: Pagination, currencyCode?: CurrencyCode) => { diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index f0a08d7f3f..dc7a5d4ce0 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -174,5 +174,3 @@ export default async function RootLayout({ params, children }: Props) { export function generateStaticParams() { return routing.locales.map((locale) => ({ locale })); } - -export const fetchCache = 'default-cache'; diff --git a/core/app/favicon.ico/route.ts b/core/app/favicon.ico/route.ts index 49df80d88d..5b2428b8a9 100644 --- a/core/app/favicon.ico/route.ts +++ b/core/app/favicon.ico/route.ts @@ -47,5 +47,3 @@ export const GET = async () => { }, }); }; - -export const dynamic = 'force-static'; diff --git a/core/app/robots.txt/route.ts b/core/app/robots.txt/route.ts index 24b6b1d3c3..223801f2f4 100644 --- a/core/app/robots.txt/route.ts +++ b/core/app/robots.txt/route.ts @@ -55,5 +55,3 @@ export const GET = async () => { }, }); }; - -export const dynamic = 'force-static'; diff --git a/core/next.config.ts b/core/next.config.ts index 1f39548d60..b7dc84bd40 100644 --- a/core/next.config.ts +++ b/core/next.config.ts @@ -64,6 +64,7 @@ export default async (): Promise => { reactStrictMode: true, experimental: { optimizePackageImports: ['@icons-pack/react-simple-icons'], + cacheComponents: true, }, typescript: { ignoreBuildErrors: !!process.env.CI, From 5fd25a678d2718f82b53794fe2aedc13323e0b7b Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 14:37:07 -0600 Subject: [PATCH 11/24] fix: remove force-dynamic in route --- core/app/[locale]/(default)/(auth)/login/token/[token]/route.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/app/[locale]/(default)/(auth)/login/token/[token]/route.ts b/core/app/[locale]/(default)/(auth)/login/token/[token]/route.ts index 16f806330a..e7e092e828 100644 --- a/core/app/[locale]/(default)/(auth)/login/token/[token]/route.ts +++ b/core/app/[locale]/(default)/(auth)/login/token/[token]/route.ts @@ -35,5 +35,3 @@ export async function GET(_: Request, { params }: { params: Promise<{ token: str redirect(`/login?error=InvalidToken`); } } - -export const dynamic = 'force-dynamic'; From 011c43785c41c597b772d0a988731b234ebc10a0 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 14:47:28 -0600 Subject: [PATCH 12/24] fix: remove correlation-id --- core/client/correlation-id.ts | 8 -------- core/client/index.ts | 3 --- 2 files changed, 11 deletions(-) delete mode 100644 core/client/correlation-id.ts diff --git a/core/client/correlation-id.ts b/core/client/correlation-id.ts deleted file mode 100644 index f3ce208e1a..0000000000 --- a/core/client/correlation-id.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { cache } from 'react'; - -/** - * Returns a stable correlation ID for the current request. - * React.cache ensures the same UUID is returned for all fetches within a - * single page render, while being unique across renders/requests. - */ -export const getCorrelationId = cache((): string => crypto.randomUUID()); diff --git a/core/client/index.ts b/core/client/index.ts index b153aea4ab..70e8149b75 100644 --- a/core/client/index.ts +++ b/core/client/index.ts @@ -13,7 +13,6 @@ import { backendUserAgent } from '../user-agent'; // During config resolution, the dynamic import of next-intl/server succeeds but // getLocale() throws ("not supported in Client Components") — the try/catch // below absorbs this gracefully, and getChannelId falls back to defaultChannelId. -import { getCorrelationId } from './correlation-id'; export const client = createClient({ storefrontToken: process.env.BIGCOMMERCE_STOREFRONT_TOKEN ?? '', @@ -40,8 +39,6 @@ export const client = createClient({ } } - requestHeaders['X-Correlation-ID'] = getCorrelationId(); - return { headers: requestHeaders, }; From ca89e5f9879cd65da0cb49cc39128602b7b88dce Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 14:55:06 -0600 Subject: [PATCH 13/24] fix: issue with Date --- core/components/footer/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/components/footer/index.tsx b/core/components/footer/index.tsx index 8148c2c035..63012ad164 100644 --- a/core/components/footer/index.tsx +++ b/core/components/footer/index.tsx @@ -7,6 +7,7 @@ import { SiYoutube, } from '@icons-pack/react-simple-icons'; import { getTranslations } from 'next-intl/server'; +import { connection } from 'next/server'; import { cache, JSX } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; @@ -72,6 +73,7 @@ const getFooterData = cache(async () => { }); export const Footer = async () => { + await connection(); const t = await getTranslations('Components.Footer'); const data = await getFooterData(); From 347cab31a3cb94c6d41db694aabb114fc469c9c3 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 15:48:18 -0600 Subject: [PATCH 14/24] fix: issues with cache components --- .../(default)/(auth)/change-password/page.tsx | 24 +++++-- core/app/[locale]/(default)/(auth)/layout.tsx | 18 +++++- .../[locale]/(default)/(auth)/login/page.tsx | 26 ++++++-- .../account/orders/[id]/page-data.tsx | 5 +- .../(default)/account/orders/[id]/page.tsx | 10 ++- .../(default)/account/orders/page-data.ts | 3 +- .../(default)/account/orders/page.tsx | 25 +++++--- .../(default)/account/settings/page-data.tsx | 63 +++++++++---------- .../(default)/account/settings/page.tsx | 10 ++- core/next.config.ts | 2 +- 10 files changed, 119 insertions(+), 67 deletions(-) diff --git a/core/app/[locale]/(default)/(auth)/change-password/page.tsx b/core/app/[locale]/(default)/(auth)/change-password/page.tsx index fe8f70832d..70de8e2e8b 100644 --- a/core/app/[locale]/(default)/(auth)/change-password/page.tsx +++ b/core/app/[locale]/(default)/(auth)/change-password/page.tsx @@ -1,6 +1,7 @@ /* eslint-disable react/jsx-no-bind */ import { Metadata } from 'next'; import { getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { ResetPasswordSection } from '@/vibes/soul/sections/reset-password-section'; import { getChangePasswordQuery } from '~/app/[locale]/(default)/(auth)/change-password/page-data'; @@ -26,13 +27,14 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function ChangePassword({ params, searchParams }: Props) { - const { locale } = await params; - - setRequestLocale(locale); +interface ContentProps { + searchParams: Promise<{ c?: string; t?: string }>; + locale: string; +} +async function ChangePasswordContent({ searchParams, locale }: ContentProps) { const { c: customerEntityId, t: token } = await searchParams; - const t = await getTranslations('Auth.ChangePassword'); + const t = await getTranslations({ locale, namespace: 'Auth.ChangePassword' }); if (!customerEntityId || !token) { return redirect({ href: '/login', locale }); @@ -50,3 +52,15 @@ export default async function ChangePassword({ params, searchParams }: Props) { /> ); } + +export default async function ChangePassword({ params, searchParams }: Props) { + const { locale } = await params; + + setRequestLocale(locale); + + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/(auth)/layout.tsx b/core/app/[locale]/(default)/(auth)/layout.tsx index cdccae9970..b56d804dfa 100644 --- a/core/app/[locale]/(default)/(auth)/layout.tsx +++ b/core/app/[locale]/(default)/(auth)/layout.tsx @@ -1,4 +1,5 @@ -import { PropsWithChildren } from 'react'; +import { setRequestLocale } from 'next-intl/server'; +import { PropsWithChildren, Suspense } from 'react'; import { isLoggedIn } from '~/auth'; import { redirect } from '~/i18n/routing'; @@ -7,9 +8,8 @@ interface Props extends PropsWithChildren { params: Promise<{ locale: string }>; } -export default async function Layout({ children, params }: Props) { +async function AuthCheck({ locale, children }: { locale: string; children: React.ReactNode }) { const loggedIn = await isLoggedIn(); - const { locale } = await params; if (loggedIn) { redirect({ href: '/account/orders', locale }); @@ -17,3 +17,15 @@ export default async function Layout({ children, params }: Props) { return children; } + +export default async function Layout({ children, params }: Props) { + const { locale } = await params; + + setRequestLocale(locale); + + return ( + + {children} + + ); +} diff --git a/core/app/[locale]/(default)/(auth)/login/page.tsx b/core/app/[locale]/(default)/(auth)/login/page.tsx index dadb1eeb5c..80eeae2a4c 100644 --- a/core/app/[locale]/(default)/(auth)/login/page.tsx +++ b/core/app/[locale]/(default)/(auth)/login/page.tsx @@ -1,6 +1,7 @@ /* eslint-disable react/jsx-no-bind */ import { Metadata } from 'next'; import { getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { ButtonLink } from '@/vibes/soul/primitives/button-link'; import { SignInSection } from '@/vibes/soul/sections/sign-in-section'; @@ -27,13 +28,16 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function Login({ params, searchParams }: Props) { - const { locale } = await params; +async function LoginContent({ + searchParams, + locale, +}: { + searchParams: Props['searchParams']; + locale: string; +}) { const { redirectTo = '/account/orders', error } = await searchParams; - setRequestLocale(locale); - - const t = await getTranslations('Auth.Login'); + const t = await getTranslations({ locale, namespace: 'Auth.Login' }); const vanityUrl = buildConfig.get('urls').vanityUrl; const redirectUrl = new URL(redirectTo, vanityUrl); @@ -75,3 +79,15 @@ export default async function Login({ params, searchParams }: Props) { ); } + +export default async function Login({ params, searchParams }: Props) { + const { locale } = await params; + + setRequestLocale(locale); + + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/account/orders/[id]/page-data.tsx b/core/app/[locale]/(default)/account/orders/[id]/page-data.tsx index 9fd6c21afc..c69981298a 100644 --- a/core/app/[locale]/(default)/account/orders/[id]/page-data.tsx +++ b/core/app/[locale]/(default)/account/orders/[id]/page-data.tsx @@ -1,7 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { cache } from 'react'; -import { getSessionCustomerAccessToken } from '~/auth'; import { client } from '~/client'; import { graphql } from '~/client/graphql'; import { TAGS } from '~/client/tags'; @@ -155,9 +154,7 @@ const CustomerOrderDetails = graphql( [OrderItemFragment, OrderGiftCertificateItemFragment], ); -export const getCustomerOrderDetails = cache(async (id: number) => { - const customerAccessToken = await getSessionCustomerAccessToken(); - +export const getCustomerOrderDetails = cache(async (id: number, customerAccessToken?: string) => { const response = await client.fetch({ document: CustomerOrderDetails, variables: { diff --git a/core/app/[locale]/(default)/account/orders/[id]/page.tsx b/core/app/[locale]/(default)/account/orders/[id]/page.tsx index 20e166389f..e534d907f6 100644 --- a/core/app/[locale]/(default)/account/orders/[id]/page.tsx +++ b/core/app/[locale]/(default)/account/orders/[id]/page.tsx @@ -3,6 +3,7 @@ import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/serve import { Streamable } from '@/vibes/soul/lib/streamable'; import { OrderDetailsSection } from '@/vibes/soul/sections/order-details-section'; +import { getSessionCustomerAccessToken } from '~/auth'; import { orderDetailsTransformer } from '~/data-transformers/order-details-transformer'; import { getCustomerOrderDetails } from './page-data'; @@ -19,11 +20,14 @@ export default async function OrderDetails(props: Props) { setRequestLocale(locale); - const t = await getTranslations('Account.Orders.Details'); - const format = await getFormatter(); + const [t, format] = await Promise.all([ + getTranslations('Account.Orders.Details'), + getFormatter(), + ]); const streamableOrder = Streamable.from(async () => { - const order = await getCustomerOrderDetails(Number(id)); + const customerAccessToken = await getSessionCustomerAccessToken(); + const order = await getCustomerOrderDetails(Number(id), customerAccessToken); if (!order) { notFound(); diff --git a/core/app/[locale]/(default)/account/orders/page-data.ts b/core/app/[locale]/(default)/account/orders/page-data.ts index bf67b08311..85b3f32c9f 100644 --- a/core/app/[locale]/(default)/account/orders/page-data.ts +++ b/core/app/[locale]/(default)/account/orders/page-data.ts @@ -1,7 +1,6 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { cache } from 'react'; -import { getSessionCustomerAccessToken } from '~/auth'; import { client } from '~/client'; import { PaginationFragment } from '~/client/fragments/pagination'; import { graphql, VariablesOf } from '~/client/graphql'; @@ -92,8 +91,8 @@ export const getCustomerOrders = cache( async ( locale: string, { before = '', after = '', filterByStatus, filterByDateRange, limit = 5 }: CustomerOrdersArgs, + customerAccessToken?: string, ) => { - const customerAccessToken = await getSessionCustomerAccessToken(); const paginationArgs = before ? { last: limit, before } : { first: limit, after }; const filtersArgs = { filters: { diff --git a/core/app/[locale]/(default)/account/orders/page.tsx b/core/app/[locale]/(default)/account/orders/page.tsx index aad96c1f18..6639eb94e3 100644 --- a/core/app/[locale]/(default)/account/orders/page.tsx +++ b/core/app/[locale]/(default)/account/orders/page.tsx @@ -1,6 +1,7 @@ import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { Order, OrderList } from '@/vibes/soul/sections/order-list'; +import { getSessionCustomerAccessToken } from '~/auth'; import { ordersTransformer } from '~/data-transformers/orders-transformer'; import { defaultPageInfo, pageInfoTransformer } from '~/data-transformers/page-info-transformer'; @@ -16,11 +17,15 @@ interface Props { } async function getOrders(locale: string, after?: string, before?: string): Promise { - const format = await getFormatter(); - const customerOrdersDetails = await getCustomerOrders(locale, { - ...(after && { after }), - ...(before && { before }), - }); + const [format, customerAccessToken] = await Promise.all([ + getFormatter(), + getSessionCustomerAccessToken(), + ]); + const customerOrdersDetails = await getCustomerOrders( + locale, + { ...(after && { after }), ...(before && { before }) }, + customerAccessToken, + ); if (!customerOrdersDetails) { return []; @@ -32,10 +37,12 @@ async function getOrders(locale: string, after?: string, before?: string): Promi } async function getPaginationInfo(locale: string, after?: string, before?: string) { - const customerOrdersDetails = await getCustomerOrders(locale, { - ...(after && { after }), - ...(before && { before }), - }); + const customerAccessToken = await getSessionCustomerAccessToken(); + const customerOrdersDetails = await getCustomerOrders( + locale, + { ...(after && { after }), ...(before && { before }) }, + customerAccessToken, + ); return pageInfoTransformer(customerOrdersDetails?.pageInfo ?? defaultPageInfo); } diff --git a/core/app/[locale]/(default)/account/settings/page-data.tsx b/core/app/[locale]/(default)/account/settings/page-data.tsx index 136ef5c991..5c26cf569e 100644 --- a/core/app/[locale]/(default)/account/settings/page-data.tsx +++ b/core/app/[locale]/(default)/account/settings/page-data.tsx @@ -1,6 +1,5 @@ import { cache } from 'react'; -import { getSessionCustomerAccessToken } from '~/auth'; import { client } from '~/client'; import { graphql, VariablesOf } from '~/client/graphql'; import { TAGS } from '~/client/tags'; @@ -67,37 +66,37 @@ interface Props { }; } -export const getAccountSettingsQuery = cache(async ({ address, customer }: Props = {}) => { - const customerAccessToken = await getSessionCustomerAccessToken(); +export const getAccountSettingsQuery = cache( + async ({ address, customer }: Props = {}, customerAccessToken?: string) => { + const response = await client.fetch({ + document: AccountSettingsQuery, + variables: { + addressFilters: address?.filters, + addressSortBy: address?.sortBy, + customerFilters: customer?.filters, + customerSortBy: customer?.sortBy, + }, + fetchOptions: { cache: 'no-store', next: { tags: [TAGS.customer] } }, + customerAccessToken, + }); - const response = await client.fetch({ - document: AccountSettingsQuery, - variables: { - addressFilters: address?.filters, - addressSortBy: address?.sortBy, - customerFilters: customer?.filters, - customerSortBy: customer?.sortBy, - }, - fetchOptions: { cache: 'no-store', next: { tags: [TAGS.customer] } }, - customerAccessToken, - }); + const addressFields = response.data.site.settings?.formFields.shippingAddress; + const customerFields = response.data.site.settings?.formFields.customer; + const customerInfo = response.data.customer; + const newsletterSettings = response.data.site.settings?.newsletter; + const passwordComplexitySettings = + response.data.site.settings?.customers?.passwordComplexitySettings; - const addressFields = response.data.site.settings?.formFields.shippingAddress; - const customerFields = response.data.site.settings?.formFields.customer; - const customerInfo = response.data.customer; - const newsletterSettings = response.data.site.settings?.newsletter; - const passwordComplexitySettings = - response.data.site.settings?.customers?.passwordComplexitySettings; - - if (!addressFields || !customerFields || !customerInfo) { - return null; - } + if (!addressFields || !customerFields || !customerInfo) { + return null; + } - return { - addressFields, - customerFields, - customerInfo, - newsletterSettings, - passwordComplexitySettings, - }; -}); + return { + addressFields, + customerFields, + customerInfo, + newsletterSettings, + passwordComplexitySettings, + }; + }, +); diff --git a/core/app/[locale]/(default)/account/settings/page.tsx b/core/app/[locale]/(default)/account/settings/page.tsx index cad145dc6f..6e819c0c37 100644 --- a/core/app/[locale]/(default)/account/settings/page.tsx +++ b/core/app/[locale]/(default)/account/settings/page.tsx @@ -5,6 +5,8 @@ import { getTranslations, setRequestLocale } from 'next-intl/server'; import { AccountSettingsSection } from '@/vibes/soul/sections/account-settings'; +import { getSessionCustomerAccessToken } from '~/auth'; + import { changePassword } from './_actions/change-password'; import { updateCustomer } from './_actions/update-customer'; import { updateNewsletterSubscription } from './_actions/update-newsletter-subscription'; @@ -29,9 +31,11 @@ export default async function Settings({ params }: Props) { setRequestLocale(locale); - const t = await getTranslations('Account.Settings'); - - const accountSettings = await getAccountSettingsQuery(); + const [t, customerAccessToken] = await Promise.all([ + getTranslations('Account.Settings'), + getSessionCustomerAccessToken(), + ]); + const accountSettings = await getAccountSettingsQuery({}, customerAccessToken); if (!accountSettings) { notFound(); diff --git a/core/next.config.ts b/core/next.config.ts index b7dc84bd40..794bc98b37 100644 --- a/core/next.config.ts +++ b/core/next.config.ts @@ -64,8 +64,8 @@ export default async (): Promise => { reactStrictMode: true, experimental: { optimizePackageImports: ['@icons-pack/react-simple-icons'], - cacheComponents: true, }, + cacheComponents: true, typescript: { ignoreBuildErrors: !!process.env.CI, }, From ae3714f5e84e8671853e80597ca560a2ec80be3d Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 16:05:01 -0600 Subject: [PATCH 15/24] fix: suspense toast notifications --- core/app/[locale]/layout.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index dc7a5d4ce0..f4fd3640ab 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -6,7 +6,7 @@ import { notFound } from 'next/navigation'; import { NextIntlClientProvider } from 'next-intl'; import { setRequestLocale } from 'next-intl/server'; import { NuqsAdapter } from 'nuqs/adapters/next/app'; -import { cache, PropsWithChildren } from 'react'; +import { cache, PropsWithChildren, Suspense } from 'react'; import '../../globals.css'; @@ -116,6 +116,12 @@ const VercelComponents = () => { ); }; +async function ToastNotification() { + const toastData = await getToastNotification(); + if (!toastData) return null; + return ; +} + interface Props extends PropsWithChildren { params: Promise<{ locale: string }>; } @@ -124,7 +130,6 @@ export default async function RootLayout({ params, children }: Props) { const { locale } = await params; const rootData = await fetchRootLayoutMetadata(); - const toastNotificationCookieData = await getToastNotification(); if (!routing.locales.includes(locale)) { notFound(); @@ -155,9 +160,9 @@ export default async function RootLayout({ params, children }: Props) { settings={rootData.data.site.settings} > - {toastNotificationCookieData && ( - - )} + + + {children} From e995454f93cb5651dc1e1fb902ae66c00c2d371e Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 16:09:53 -0600 Subject: [PATCH 16/24] fix: use counter instead of uuid in streamable --- core/vibes/soul/lib/streamable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vibes/soul/lib/streamable.tsx b/core/vibes/soul/lib/streamable.tsx index ad98eeadc6..74c6b116af 100644 --- a/core/vibes/soul/lib/streamable.tsx +++ b/core/vibes/soul/lib/streamable.tsx @@ -1,12 +1,12 @@ import PLazy from 'p-lazy'; import { Suspense, use } from 'react'; -import { v4 as uuid } from 'uuid'; export type Streamable = T | Promise; // eslint-disable-next-line func-names const stableKeys = (function () { const cache = new WeakMap(); + let counter = 0; function getObjectKey(obj: object): string { const key = cache.get(obj); @@ -15,7 +15,7 @@ const stableKeys = (function () { return key; } - const keyValue = uuid(); + const keyValue = String(counter++); cache.set(obj, keyValue); From 2ad058683a4cfb9251095256941c6a87fa1cf25c Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 4 Mar 2026 17:25:47 -0600 Subject: [PATCH 17/24] fix: more stream fixes --- core/app/[locale]/layout.tsx | 8 +++++- core/lib/search.tsx | 2 ++ .../soul/primitives/navigation/index.tsx | 27 +++++++++++-------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index f4fd3640ab..9bdce3aec9 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -2,6 +2,7 @@ import { Analytics } from '@vercel/analytics/react'; import { SpeedInsights } from '@vercel/speed-insights/next'; import { clsx } from 'clsx'; import type { Metadata } from 'next'; +import { cacheLife } from 'next/cache'; import { notFound } from 'next/navigation'; import { NextIntlClientProvider } from 'next-intl'; import { setRequestLocale } from 'next-intl/server'; @@ -58,9 +59,12 @@ const RootLayoutMetadataQuery = graphql( ); const fetchRootLayoutMetadata = cache(async () => { + 'use cache'; + + cacheLife({ revalidate }); + return await client.fetch({ document: RootLayoutMetadataQuery, - fetchOptions: { next: { revalidate } }, }); }); @@ -118,7 +122,9 @@ const VercelComponents = () => { async function ToastNotification() { const toastData = await getToastNotification(); + if (!toastData) return null; + return ; } diff --git a/core/lib/search.tsx b/core/lib/search.tsx index 8a188fe9fa..375cf83330 100644 --- a/core/lib/search.tsx +++ b/core/lib/search.tsx @@ -1,3 +1,5 @@ +'use client'; + import React, { createContext, Dispatch, diff --git a/core/vibes/soul/primitives/navigation/index.tsx b/core/vibes/soul/primitives/navigation/index.tsx index f539252327..d9e716a56f 100644 --- a/core/vibes/soul/primitives/navigation/index.tsx +++ b/core/vibes/soul/primitives/navigation/index.tsx @@ -19,6 +19,7 @@ import { useParams, useSearchParams } from 'next/navigation'; import React, { forwardRef, Ref, + Suspense, useActionState, useCallback, useEffect, @@ -407,11 +408,13 @@ export const Navigation = forwardRef(function Navigation
{/* Locale / Language Dropdown */} {locales.length > 1 ? ( - + + + ) : null} {/* Currency Dropdown */} @@ -625,12 +628,14 @@ export const Navigation = forwardRef(function Navigation {/* Locale / Language Dropdown */} {locales && locales.length > 1 ? ( - + + + ) : null} {/* Currency Dropdown */} From 8492c998d229ceb6a69d801fe77b49e2844cec54 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Thu, 5 Mar 2026 11:50:13 -0600 Subject: [PATCH 18/24] fix: cache extra queries --- core/app/[locale]/layout.tsx | 4 ++- core/components/footer/index.tsx | 53 ++++++++++++++++++++++---------- core/components/header/index.tsx | 35 +++++++++++++++++---- core/lib/seo/canonical.ts | 5 +++ 4 files changed, 74 insertions(+), 23 deletions(-) diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index 9bdce3aec9..062cb6c8ab 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -176,7 +176,9 @@ export default async function RootLayout({ params, children }: Props) { - + + + ); diff --git a/core/components/footer/index.tsx b/core/components/footer/index.tsx index 63012ad164..41cfbf6d81 100644 --- a/core/components/footer/index.tsx +++ b/core/components/footer/index.tsx @@ -6,8 +6,8 @@ import { SiX, SiYoutube, } from '@icons-pack/react-simple-icons'; +import { cacheLife } from 'next/cache'; import { getTranslations } from 'next-intl/server'; -import { connection } from 'next/server'; import { cache, JSX } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; @@ -47,39 +47,60 @@ const socialIcons: Record = { YouTube: { icon: }, }; +const cachedGetFooterSections = cache(async (currencyCode?: CurrencyCode) => { + 'use cache'; + + cacheLife({ revalidate }); + + const { data: response } = await client.fetch({ + document: GetLinksAndSectionsQuery, + variables: { currencyCode }, + fetchOptions: { next: { revalidate } }, + }); + + return readFragment(FooterSectionsFragment, response).site; +}); + const getFooterSections = cache( async (customerAccessToken?: string, currencyCode?: CurrencyCode) => { - const { data: response } = await client.fetch({ - document: GetLinksAndSectionsQuery, - customerAccessToken, - variables: { currencyCode }, - // Since this query is needed on every page, it's a good idea not to validate the customer access token. - // The 'cache' function also caches errors, so we might get caught in a redirect loop if the cache saves an invalid token error response. - validateCustomerAccessToken: false, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, - }); - - return readFragment(FooterSectionsFragment, response).site; + if (customerAccessToken) { + const { data: response } = await client.fetch({ + document: GetLinksAndSectionsQuery, + customerAccessToken, + variables: { currencyCode }, + // Since this query is needed on every page, it's a good idea not to validate the customer access token. + // The 'cache' function also caches errors, so we might get caught in a redirect loop if the cache saves an invalid token error response. + validateCustomerAccessToken: false, + fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + }); + + return readFragment(FooterSectionsFragment, response).site; + } + + return cachedGetFooterSections(currencyCode); }, ); const getFooterData = cache(async () => { + 'use cache'; + + cacheLife({ revalidate }); + const { data: response } = await client.fetch({ document: LayoutQuery, fetchOptions: { next: { revalidate } }, }); - return readFragment(FooterFragment, response).site; + return { site: readFragment(FooterFragment, response).site, year: new Date().getFullYear() }; }); export const Footer = async () => { - await connection(); const t = await getTranslations('Components.Footer'); - const data = await getFooterData(); + const { site: data, year } = await getFooterData(); const logo = data.settings ? logoTransformer(data.settings) : ''; - const copyright = `© ${new Date().getFullYear()} ${data.settings?.storeName} – Powered by BigCommerce`; + const copyright = `© ${year} ${data.settings?.storeName} – Powered by BigCommerce`; const contactInformation = data.settings?.contact ? { diff --git a/core/components/header/index.tsx b/core/components/header/index.tsx index f686f8d65d..5f1a5101e3 100644 --- a/core/components/header/index.tsx +++ b/core/components/header/index.tsx @@ -1,3 +1,4 @@ +import { cacheLife } from 'next/cache'; import { getLocale, getTranslations } from 'next-intl/server'; import { cache } from 'react'; @@ -47,21 +48,43 @@ const getCartCount = cache(async (cartId: string, customerAccessToken?: string) return response.data.site.cart?.lineItems.totalQuantity ?? null; }); -const getHeaderLinks = cache(async (customerAccessToken?: string, currencyCode?: CurrencyCode) => { +const cachedGetHeaderLinks = cache(async (currencyCode?: CurrencyCode) => { + 'use cache'; + + cacheLife({ revalidate }); + const { data: response } = await client.fetch({ document: GetLinksAndSectionsQuery, - customerAccessToken, variables: { currencyCode }, - // Since this query is needed on every page, it's a good idea not to validate the customer access token. - // The 'cache' function also caches errors, so we might get caught in a redirect loop if the cache saves an invalid token error response. - validateCustomerAccessToken: false, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { next: { revalidate } }, }); return readFragment(HeaderLinksFragment, response).site; }); +const getHeaderLinks = cache(async (customerAccessToken?: string, currencyCode?: CurrencyCode) => { + if (customerAccessToken) { + const { data: response } = await client.fetch({ + document: GetLinksAndSectionsQuery, + customerAccessToken, + variables: { currencyCode }, + // Since this query is needed on every page, it's a good idea not to validate the customer access token. + // The 'cache' function also caches errors, so we might get caught in a redirect loop if the cache saves an invalid token error response. + validateCustomerAccessToken: false, + fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + }); + + return readFragment(HeaderLinksFragment, response).site; + } + + return cachedGetHeaderLinks(currencyCode); +}); + const getHeaderData = cache(async () => { + 'use cache'; + + cacheLife({ revalidate }); + const { data: response } = await client.fetch({ document: LayoutQuery, fetchOptions: { next: { revalidate } }, diff --git a/core/lib/seo/canonical.ts b/core/lib/seo/canonical.ts index dd1573947a..8f0e0d8397 100644 --- a/core/lib/seo/canonical.ts +++ b/core/lib/seo/canonical.ts @@ -1,3 +1,4 @@ +import { cacheLife } from 'next/cache'; import { cache } from 'react'; import { client } from '~/client'; @@ -46,6 +47,10 @@ const VanityUrlQuery = graphql(` `); const getVanityUrl = cache(async () => { + 'use cache'; + + cacheLife({ revalidate }); + const { data } = await client.fetch({ document: VanityUrlQuery, fetchOptions: { next: { revalidate } }, From eccc8473a12401ca495b8f4478458a3bd92bb086 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Thu, 5 Mar 2026 11:58:57 -0600 Subject: [PATCH 19/24] fix: cache reviews --- .../(default)/product/[slug]/_components/reviews.tsx | 6 +++++- core/components/footer/index.tsx | 1 - core/components/header/index.tsx | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/app/[locale]/(default)/product/[slug]/_components/reviews.tsx b/core/app/[locale]/(default)/product/[slug]/_components/reviews.tsx index 6429de74be..4160f5fa9e 100644 --- a/core/app/[locale]/(default)/product/[slug]/_components/reviews.tsx +++ b/core/app/[locale]/(default)/product/[slug]/_components/reviews.tsx @@ -1,4 +1,5 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; +import { cacheLife } from 'next/cache'; import { getFormatter, getTranslations } from 'next-intl/server'; import { createLoader, parseAsString, SearchParams } from 'nuqs/server'; import { cache } from 'react'; @@ -65,10 +66,13 @@ const ReviewsQuery = graphql( ); const getReviews = cache(async (productId: number, paginationArgs: object) => { + 'use cache'; + + cacheLife({ revalidate }); + const { data } = await client.fetch({ document: ReviewsQuery, variables: { ...paginationArgs, entityId: productId }, - fetchOptions: { next: { revalidate } }, }); return data.site.product; diff --git a/core/components/footer/index.tsx b/core/components/footer/index.tsx index 41cfbf6d81..b9103b4f3c 100644 --- a/core/components/footer/index.tsx +++ b/core/components/footer/index.tsx @@ -88,7 +88,6 @@ const getFooterData = cache(async () => { const { data: response } = await client.fetch({ document: LayoutQuery, - fetchOptions: { next: { revalidate } }, }); return { site: readFragment(FooterFragment, response).site, year: new Date().getFullYear() }; diff --git a/core/components/header/index.tsx b/core/components/header/index.tsx index 5f1a5101e3..8b72bdbd44 100644 --- a/core/components/header/index.tsx +++ b/core/components/header/index.tsx @@ -87,7 +87,6 @@ const getHeaderData = cache(async () => { const { data: response } = await client.fetch({ document: LayoutQuery, - fetchOptions: { next: { revalidate } }, }); return readFragment(HeaderFragment, response).site; From ac9f5c633096e5e22602ded70d8986cb960ea27a Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Thu, 5 Mar 2026 13:35:20 -0600 Subject: [PATCH 20/24] fix: wrap pages in Suspense --- .../(default)/(faceted)/brand/[slug]/page.tsx | 11 ++++++++- .../(faceted)/category/[slug]/page.tsx | 11 ++++++++- .../(default)/account/addresses/page.tsx | 11 ++++++++- .../(default)/account/orders/[id]/page.tsx | 11 ++++++++- .../(default)/account/orders/page.tsx | 11 ++++++++- .../(default)/account/settings/page.tsx | 11 ++++++++- .../(default)/account/wishlists/[id]/page.tsx | 11 ++++++++- .../(default)/account/wishlists/page.tsx | 11 ++++++++- .../[locale]/(default)/blog/[blogId]/page.tsx | 19 ++++++++++++--- core/app/[locale]/(default)/blog/page.tsx | 11 ++++++++- core/app/[locale]/(default)/cart/loading.tsx | 2 ++ core/app/[locale]/(default)/cart/page.tsx | 11 ++++++++- .../gift-certificates/balance/page.tsx | 11 ++++++++- .../(default)/gift-certificates/page.tsx | 11 ++++++++- .../gift-certificates/purchase/page.tsx | 11 ++++++++- core/app/[locale]/(default)/layout.tsx | 6 +++-- .../(default)/product/[slug]/page.tsx | 11 ++++++++- .../(default)/webpages/[id]/contact/page.tsx | 12 ++++++++-- .../(default)/webpages/[id]/layout.tsx | 23 ++++++++++++++++--- .../(default)/webpages/[id]/normal/page.tsx | 12 ++++++++-- .../(default)/wishlist/[token]/page.tsx | 11 ++++++++- core/app/[locale]/maintenance/page.tsx | 12 ++++++++-- 22 files changed, 222 insertions(+), 29 deletions(-) diff --git a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx index ba091c43ff..f9fa9ea10d 100644 --- a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx @@ -5,6 +5,7 @@ import { createLoader, SearchParams } from 'nuqs/server'; import { cache } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; +import { Suspense } from 'react'; import { createCompareLoader } from '@/vibes/soul/primitives/compare-drawer/loader'; import { ProductsListSection } from '@/vibes/soul/sections/products-list-section'; import { getFilterParsers } from '@/vibes/soul/sections/products-list-section/filter-parsers'; @@ -94,7 +95,7 @@ export async function generateMetadata(props: Props): Promise { }; } -export default async function Brand(props: Props) { +async function BrandContent(props: Props) { const { locale, slug } = await props.params; const customerAccessToken = await getSessionCustomerAccessToken(); @@ -255,3 +256,11 @@ export default async function Brand(props: Props) { /> ); } + +export default function Brand(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx index 74c532cbb7..e3fe6d1f77 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx @@ -6,6 +6,7 @@ import { createLoader, SearchParams } from 'nuqs/server'; import { cache } from 'react'; import { Stream, Streamable } from '@/vibes/soul/lib/streamable'; +import { Suspense } from 'react'; import { createCompareLoader } from '@/vibes/soul/primitives/compare-drawer/loader'; import { ProductsListSection } from '@/vibes/soul/sections/products-list-section'; import { getFilterParsers } from '@/vibes/soul/sections/products-list-section/filter-parsers'; @@ -101,7 +102,7 @@ export async function generateMetadata(props: Props): Promise { }; } -export default async function Category(props: Props) { +async function CategoryContent(props: Props) { const { slug, locale } = await props.params; const customerAccessToken = await getSessionCustomerAccessToken(); @@ -303,3 +304,11 @@ export default async function Category(props: Props) { ); } + +export default function Category(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/account/addresses/page.tsx b/core/app/[locale]/(default)/account/addresses/page.tsx index 865ba4f575..1fa0b82cc5 100644 --- a/core/app/[locale]/(default)/account/addresses/page.tsx +++ b/core/app/[locale]/(default)/account/addresses/page.tsx @@ -1,6 +1,7 @@ import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { Address, AddressListSection } from '@/vibes/soul/sections/address-list-section'; import { getSessionCustomerAccessToken } from '~/auth'; @@ -37,7 +38,7 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function Addresses({ params, searchParams }: Props) { +async function AddressesContent({ params, searchParams }: Props) { const { locale } = await params; setRequestLocale(locale); @@ -119,3 +120,11 @@ export default async function Addresses({ params, searchParams }: Props) { /> ); } + +export default function Addresses(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/account/orders/[id]/page.tsx b/core/app/[locale]/(default)/account/orders/[id]/page.tsx index e534d907f6..8adb7ab81b 100644 --- a/core/app/[locale]/(default)/account/orders/[id]/page.tsx +++ b/core/app/[locale]/(default)/account/orders/[id]/page.tsx @@ -1,5 +1,6 @@ import { notFound } from 'next/navigation'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; import { OrderDetailsSection } from '@/vibes/soul/sections/order-details-section'; @@ -15,7 +16,7 @@ interface Props { }>; } -export default async function OrderDetails(props: Props) { +async function OrderDetailsContent(props: Props) { const { id, locale } = await props.params; setRequestLocale(locale); @@ -48,3 +49,11 @@ export default async function OrderDetails(props: Props) { /> ); } + +export default function OrderDetails(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/account/orders/page.tsx b/core/app/[locale]/(default)/account/orders/page.tsx index 6639eb94e3..609678a587 100644 --- a/core/app/[locale]/(default)/account/orders/page.tsx +++ b/core/app/[locale]/(default)/account/orders/page.tsx @@ -1,4 +1,5 @@ import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { Order, OrderList } from '@/vibes/soul/sections/order-list'; import { getSessionCustomerAccessToken } from '~/auth'; @@ -47,7 +48,7 @@ async function getPaginationInfo(locale: string, after?: string, before?: string return pageInfoTransformer(customerOrdersDetails?.pageInfo ?? defaultPageInfo); } -export default async function Orders({ params, searchParams }: Props) { +async function OrdersContent({ params, searchParams }: Props) { const { locale } = await params; setRequestLocale(locale); @@ -68,3 +69,11 @@ export default async function Orders({ params, searchParams }: Props) { /> ); } + +export default function Orders(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/account/settings/page.tsx b/core/app/[locale]/(default)/account/settings/page.tsx index 6e819c0c37..54a60391b4 100644 --- a/core/app/[locale]/(default)/account/settings/page.tsx +++ b/core/app/[locale]/(default)/account/settings/page.tsx @@ -2,6 +2,7 @@ import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { AccountSettingsSection } from '@/vibes/soul/sections/account-settings'; @@ -26,7 +27,7 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function Settings({ params }: Props) { +async function SettingsContent({ params }: Props) { const { locale } = await params; setRequestLocale(locale); @@ -73,3 +74,11 @@ export default async function Settings({ params }: Props) { /> ); } + +export default function Settings(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx b/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx index b55be1d869..a678ecb365 100644 --- a/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx +++ b/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx @@ -1,6 +1,7 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { SearchParams } from 'nuqs'; +import { Suspense } from 'react'; import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/server'; import { Streamable } from '@/vibes/soul/lib/streamable'; @@ -119,7 +120,7 @@ async function getPaginationInfo( return pageInfoTransformer(wishlist?.items.pageInfo ?? defaultPageInfo); } -export default async function WishlistPage({ params, searchParams }: Props) { +async function WishlistPageContent({ params, searchParams }: Props) { const { locale, id } = await params; setRequestLocale(locale); @@ -185,3 +186,11 @@ export default async function WishlistPage({ params, searchParams }: Props) { ); } + +export default function WishlistPage(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/account/wishlists/page.tsx b/core/app/[locale]/(default)/account/wishlists/page.tsx index 26e9b738c0..6d08c76c67 100644 --- a/core/app/[locale]/(default)/account/wishlists/page.tsx +++ b/core/app/[locale]/(default)/account/wishlists/page.tsx @@ -1,5 +1,6 @@ import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { SearchParams } from 'nuqs'; +import { Suspense } from 'react'; import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/server'; import { Streamable } from '@/vibes/soul/lib/streamable'; @@ -78,7 +79,7 @@ async function getPaginationInfo( return pageInfoTransformer(wishlists?.pageInfo ?? defaultPageInfo); } -export default async function Wishlists({ params, searchParams }: Props) { +async function WishlistsContent({ params, searchParams }: Props) { const { locale } = await params; setRequestLocale(locale); @@ -155,3 +156,11 @@ export default async function Wishlists({ params, searchParams }: Props) { /> ); } + +export default function Wishlists(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/blog/[blogId]/page.tsx b/core/app/[locale]/(default)/blog/[blogId]/page.tsx index 49537ac9ef..1cfac2e5f1 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/page.tsx +++ b/core/app/[locale]/(default)/blog/[blogId]/page.tsx @@ -1,7 +1,9 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; -import { cache } from 'react'; +import { cache, Suspense } from 'react'; + +import { Streamable } from '@/vibes/soul/lib/streamable'; import { BlogPostContent, BlogPostContentBlogPost } from '@/vibes/soul/sections/blog-post-content'; import { Breadcrumb } from '@/vibes/soul/sections/breadcrumbs'; @@ -103,12 +105,23 @@ async function getBlogPostBreadcrumbs(props: Props): Promise { ]; } -export default async function Blog(props: Props) { +async function BlogPostPageContent(props: Props) { const { locale } = await props.params; setRequestLocale(locale); return ( - + getBlogPost(props))} + breadcrumbs={Streamable.from(() => getBlogPostBreadcrumbs(props))} + /> + ); +} + +export default function Blog(props: Props) { + return ( + + + ); } diff --git a/core/app/[locale]/(default)/blog/page.tsx b/core/app/[locale]/(default)/blog/page.tsx index f7b972f709..3de928ec80 100644 --- a/core/app/[locale]/(default)/blog/page.tsx +++ b/core/app/[locale]/(default)/blog/page.tsx @@ -5,6 +5,7 @@ import { SearchParams } from 'nuqs'; import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/server'; import { Streamable } from '@/vibes/soul/lib/streamable'; +import { Suspense } from 'react'; import { FeaturedBlogPostList } from '@/vibes/soul/sections/featured-blog-post-list'; import { defaultPageInfo, pageInfoTransformer } from '~/data-transformers/page-info-transformer'; import { getMetadataAlternates } from '~/lib/seo/canonical'; @@ -70,7 +71,7 @@ async function getPaginationInfo(locale: string, searchParamsPromise: Promise ); } + +export default function Blog(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/cart/loading.tsx b/core/app/[locale]/(default)/cart/loading.tsx index 1f0e533b4f..7704b74980 100644 --- a/core/app/[locale]/(default)/cart/loading.tsx +++ b/core/app/[locale]/(default)/cart/loading.tsx @@ -1,3 +1,5 @@ +'use client'; + import { useTranslations } from 'next-intl'; import { CartSkeleton } from '@/vibes/soul/sections/cart'; diff --git a/core/app/[locale]/(default)/cart/page.tsx b/core/app/[locale]/(default)/cart/page.tsx index 9967347516..8839730db9 100644 --- a/core/app/[locale]/(default)/cart/page.tsx +++ b/core/app/[locale]/(default)/cart/page.tsx @@ -1,5 +1,6 @@ import { Metadata } from 'next'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; import { Cart as CartComponent, CartEmptyState } from '@/vibes/soul/sections/cart'; @@ -61,7 +62,7 @@ const getAnalyticsData = async (locale: string, cartId: string, customerAccessTo }; // eslint-disable-next-line complexity -export default async function Cart({ params }: Props) { +async function CartContent({ params }: Props) { const { locale } = await params; setRequestLocale(locale); @@ -419,3 +420,11 @@ export default async function Cart({ params }: Props) { ); } + +export default function Cart(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/gift-certificates/balance/page.tsx b/core/app/[locale]/(default)/gift-certificates/balance/page.tsx index e6eca42d97..5c41063f99 100644 --- a/core/app/[locale]/(default)/gift-certificates/balance/page.tsx +++ b/core/app/[locale]/(default)/gift-certificates/balance/page.tsx @@ -1,5 +1,6 @@ import type { Metadata } from 'next'; import { getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { GiftCertificateCheckBalanceSection } from '@/vibes/soul/sections/gift-certificate-balance-section'; import { redirect } from '~/i18n/routing'; @@ -25,7 +26,7 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function GiftCertificates(props: Props) { +async function GiftCertificatesContent(props: Props) { const { locale } = await props.params; setRequestLocale(locale); @@ -63,3 +64,11 @@ export default async function GiftCertificates(props: Props) { /> ); } + +export default function GiftCertificates(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/gift-certificates/page.tsx b/core/app/[locale]/(default)/gift-certificates/page.tsx index 67e62827c0..4e1320d6cd 100644 --- a/core/app/[locale]/(default)/gift-certificates/page.tsx +++ b/core/app/[locale]/(default)/gift-certificates/page.tsx @@ -1,5 +1,6 @@ import type { Metadata } from 'next'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; +import { Suspense } from 'react'; import { GiftCertificatesSection } from '@/vibes/soul/sections/gift-certificates-section'; import { redirect } from '~/i18n/routing'; @@ -23,7 +24,7 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function GiftCertificates(props: Props) { +async function GiftCertificatesContent(props: Props) { const { locale } = await props.params; setRequestLocale(locale); @@ -55,3 +56,11 @@ export default async function GiftCertificates(props: Props) { /> ); } + +export default function GiftCertificates(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/gift-certificates/purchase/page.tsx b/core/app/[locale]/(default)/gift-certificates/purchase/page.tsx index 06d5bdc30e..d2cd3a55ed 100644 --- a/core/app/[locale]/(default)/gift-certificates/purchase/page.tsx +++ b/core/app/[locale]/(default)/gift-certificates/purchase/page.tsx @@ -1,6 +1,7 @@ import { ResultOf } from 'gql.tada'; import { Metadata } from 'next'; import { getFormatter, getTranslations } from 'next-intl/server'; +import { Suspense } from 'react'; import { Field, FieldGroup } from '@/vibes/soul/form/dynamic-form/schema'; import { GiftCertificatePurchaseSection } from '@/vibes/soul/sections/gift-certificate-purchase-section'; @@ -147,7 +148,7 @@ function getExpiryDate( } } -export default async function GiftCertificatePurchasePage({ params }: Props) { +async function GiftCertificatePurchasePageContent({ params }: Props) { const { locale } = await params; const t = await getTranslations({ locale, namespace: 'GiftCertificates' }); @@ -192,3 +193,11 @@ export default async function GiftCertificatePurchasePage({ params }: Props) { /> ); } + +export default function GiftCertificatePurchasePage(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/layout.tsx b/core/app/[locale]/(default)/layout.tsx index 95522f608e..3d9713f5fe 100644 --- a/core/app/[locale]/(default)/layout.tsx +++ b/core/app/[locale]/(default)/layout.tsx @@ -1,5 +1,5 @@ import { setRequestLocale } from 'next-intl/server'; -import { PropsWithChildren } from 'react'; +import { PropsWithChildren, Suspense } from 'react'; import { Footer } from '~/components/footer'; import { Header } from '~/components/header'; @@ -15,7 +15,9 @@ export default async function DefaultLayout({ params, children }: Props) { return ( <> -
+ +
+
{children}
diff --git a/core/app/[locale]/(default)/product/[slug]/page.tsx b/core/app/[locale]/(default)/product/[slug]/page.tsx index 07d1f446e1..a3edc6353f 100644 --- a/core/app/[locale]/(default)/product/[slug]/page.tsx +++ b/core/app/[locale]/(default)/product/[slug]/page.tsx @@ -5,6 +5,7 @@ import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/serve import { SearchParams } from 'nuqs/server'; import { Stream, Streamable } from '@/vibes/soul/lib/streamable'; +import { Suspense } from 'react'; import { FeaturedProductCarousel } from '@/vibes/soul/sections/featured-product-carousel'; import { ProductDetail } from '@/vibes/soul/sections/product-detail'; import { auth, getSessionCustomerAccessToken } from '~/auth'; @@ -64,7 +65,7 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function Product({ params, searchParams }: Props) { +async function ProductContent({ params, searchParams }: Props) { const { locale, slug } = await params; const customerAccessToken = await getSessionCustomerAccessToken(); const detachedWishlistFormId = 'product-add-to-wishlist-form'; @@ -644,3 +645,11 @@ export default async function Product({ params, searchParams }: Props) { ); } + +export default function Product(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx b/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx index 291068b27c..1a5bd769e6 100644 --- a/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx +++ b/core/app/[locale]/(default)/webpages/[id]/contact/page.tsx @@ -1,7 +1,7 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getTranslations, setRequestLocale } from 'next-intl/server'; -import { cache } from 'react'; +import { cache, Suspense } from 'react'; import { DynamicForm } from '@/vibes/soul/form/dynamic-form'; import type { Field, FieldGroup } from '@/vibes/soul/form/dynamic-form/schema'; @@ -168,7 +168,7 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function ContactPage({ params, searchParams }: Props) { +async function ContactPageContent({ params, searchParams }: Props) { const { id, locale } = await params; const { success } = await searchParams; @@ -210,3 +210,11 @@ export default async function ContactPage({ params, searchParams }: Props) { ); } + +export default function ContactPage(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/webpages/[id]/layout.tsx b/core/app/[locale]/(default)/webpages/[id]/layout.tsx index cde3f40ea5..371ca9344c 100644 --- a/core/app/[locale]/(default)/webpages/[id]/layout.tsx +++ b/core/app/[locale]/(default)/webpages/[id]/layout.tsx @@ -1,6 +1,7 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; +import { cacheLife } from 'next/cache'; import { setRequestLocale } from 'next-intl/server'; -import { cache } from 'react'; +import { cache, Suspense } from 'react'; import { SidebarMenu } from '@/vibes/soul/sections/sidebar-menu'; import { StickySidebarLayout } from '@/vibes/soul/sections/sticky-sidebar-layout'; @@ -45,7 +46,11 @@ interface PageLink { href: string; } -const getWebPageChildren = cache(async (id: string): Promise => { +async function getCachedWebPageChildren(id: string): Promise { + 'use cache'; + + cacheLife({ revalidate }); + const { data } = await client.fetch({ document: WebPageChildrenQuery, variables: { id: decodeURIComponent(id) }, @@ -73,9 +78,13 @@ const getWebPageChildren = cache(async (id: string): Promise => { return acc; }, []); +} + +const getWebPageChildren = cache(async (id: string): Promise => { + return getCachedWebPageChildren(id); }); -export default async function WebPageLayout({ params, children }: Props) { +async function WebPageLayoutContent({ params, children }: Props) { const { locale, id } = await params; setRequestLocale(locale); @@ -89,3 +98,11 @@ export default async function WebPageLayout({ params, children }: Props) { ); } + +export default function WebPageLayout(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx b/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx index 3b55299d9e..4d184072ef 100644 --- a/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx +++ b/core/app/[locale]/(default)/webpages/[id]/normal/page.tsx @@ -1,7 +1,7 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getTranslations, setRequestLocale } from 'next-intl/server'; -import { cache } from 'react'; +import { cache, Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; import { Breadcrumb } from '@/vibes/soul/sections/breadcrumbs'; @@ -73,7 +73,7 @@ export async function generateMetadata({ params }: Props): Promise { }; } -export default async function WebPage({ params }: Props) { +async function NormalWebPageContent({ params }: Props) { const { locale, id } = await params; setRequestLocale(locale); @@ -85,3 +85,11 @@ export default async function WebPage({ params }: Props) { /> ); } + +export default function WebPage(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/(default)/wishlist/[token]/page.tsx b/core/app/[locale]/(default)/wishlist/[token]/page.tsx index ab4d7bcc50..aff60394ea 100644 --- a/core/app/[locale]/(default)/wishlist/[token]/page.tsx +++ b/core/app/[locale]/(default)/wishlist/[token]/page.tsx @@ -3,6 +3,7 @@ import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { SearchParams } from 'nuqs'; +import { Suspense } from 'react'; import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/server'; import { Streamable } from '@/vibes/soul/lib/streamable'; @@ -129,7 +130,7 @@ async function getBreadcrumbs( ]; } -export default async function PublicWishlist({ params, searchParams }: Props) { +async function PublicWishlistContent({ params, searchParams }: Props) { const { locale, token } = await params; setRequestLocale(locale); @@ -200,3 +201,11 @@ export default async function PublicWishlist({ params, searchParams }: Props) { ); } + +export default function PublicWishlist(props: Props) { + return ( + + + + ); +} diff --git a/core/app/[locale]/maintenance/page.tsx b/core/app/[locale]/maintenance/page.tsx index d5bc75e4f5..0997115117 100644 --- a/core/app/[locale]/maintenance/page.tsx +++ b/core/app/[locale]/maintenance/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; import { getTranslations, setRequestLocale } from 'next-intl/server'; -import { ReactNode } from 'react'; +import { ReactNode, Suspense } from 'react'; import { Maintenance as MaintenanceSection } from '@/vibes/soul/sections/maintenance'; import { client } from '~/client'; @@ -46,7 +46,7 @@ const Container = ({ children }: { children: ReactNode }) => ( ); -export default async function Maintenance({ params }: Props) { +async function MaintenanceContent({ params }: Props) { const { locale } = await params; setRequestLocale(locale); @@ -84,3 +84,11 @@ export default async function Maintenance({ params }: Props) { ); } + +export default function Maintenance(props: Props) { + return ( + + + + ); +} From 04b48de9f2b3018d15758269d341a01fb3edae5e Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Thu, 5 Mar 2026 13:41:33 -0600 Subject: [PATCH 21/24] fix: lint --- core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx | 3 +-- .../app/[locale]/(default)/(faceted)/category/[slug]/page.tsx | 3 +-- core/app/[locale]/(default)/account/settings/page.tsx | 1 - core/app/[locale]/(default)/account/wishlists/[id]/page.tsx | 2 +- core/app/[locale]/(default)/account/wishlists/page.tsx | 2 +- core/app/[locale]/(default)/blog/[blogId]/page.tsx | 1 - core/app/[locale]/(default)/blog/page.tsx | 2 +- core/app/[locale]/(default)/product/[slug]/page.tsx | 2 +- core/app/[locale]/(default)/wishlist/[token]/page.tsx | 2 +- core/vibes/soul/lib/streamable.tsx | 4 +++- 10 files changed, 10 insertions(+), 12 deletions(-) diff --git a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx index f9fa9ea10d..01f96ffb44 100644 --- a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx @@ -2,10 +2,9 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { createLoader, SearchParams } from 'nuqs/server'; -import { cache } from 'react'; +import { cache, Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; -import { Suspense } from 'react'; import { createCompareLoader } from '@/vibes/soul/primitives/compare-drawer/loader'; import { ProductsListSection } from '@/vibes/soul/sections/products-list-section'; import { getFilterParsers } from '@/vibes/soul/sections/products-list-section/filter-parsers'; diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx index e3fe6d1f77..83eda01c0f 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx @@ -3,10 +3,9 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { createLoader, SearchParams } from 'nuqs/server'; -import { cache } from 'react'; +import { cache, Suspense } from 'react'; import { Stream, Streamable } from '@/vibes/soul/lib/streamable'; -import { Suspense } from 'react'; import { createCompareLoader } from '@/vibes/soul/primitives/compare-drawer/loader'; import { ProductsListSection } from '@/vibes/soul/sections/products-list-section'; import { getFilterParsers } from '@/vibes/soul/sections/products-list-section/filter-parsers'; diff --git a/core/app/[locale]/(default)/account/settings/page.tsx b/core/app/[locale]/(default)/account/settings/page.tsx index 54a60391b4..6f0d011388 100644 --- a/core/app/[locale]/(default)/account/settings/page.tsx +++ b/core/app/[locale]/(default)/account/settings/page.tsx @@ -5,7 +5,6 @@ import { getTranslations, setRequestLocale } from 'next-intl/server'; import { Suspense } from 'react'; import { AccountSettingsSection } from '@/vibes/soul/sections/account-settings'; - import { getSessionCustomerAccessToken } from '~/auth'; import { changePassword } from './_actions/change-password'; diff --git a/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx b/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx index a678ecb365..9b067182f6 100644 --- a/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx +++ b/core/app/[locale]/(default)/account/wishlists/[id]/page.tsx @@ -1,8 +1,8 @@ import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { SearchParams } from 'nuqs'; -import { Suspense } from 'react'; import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/server'; +import { Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; import { CursorPaginationInfo } from '@/vibes/soul/primitives/cursor-pagination'; diff --git a/core/app/[locale]/(default)/account/wishlists/page.tsx b/core/app/[locale]/(default)/account/wishlists/page.tsx index 6d08c76c67..0e803dc2d1 100644 --- a/core/app/[locale]/(default)/account/wishlists/page.tsx +++ b/core/app/[locale]/(default)/account/wishlists/page.tsx @@ -1,7 +1,7 @@ import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { SearchParams } from 'nuqs'; -import { Suspense } from 'react'; import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/server'; +import { Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; import { CursorPaginationInfo } from '@/vibes/soul/primitives/cursor-pagination'; diff --git a/core/app/[locale]/(default)/blog/[blogId]/page.tsx b/core/app/[locale]/(default)/blog/[blogId]/page.tsx index 1cfac2e5f1..5177b6937a 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/page.tsx +++ b/core/app/[locale]/(default)/blog/[blogId]/page.tsx @@ -4,7 +4,6 @@ import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/serve import { cache, Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; - import { BlogPostContent, BlogPostContentBlogPost } from '@/vibes/soul/sections/blog-post-content'; import { Breadcrumb } from '@/vibes/soul/sections/breadcrumbs'; import { getMetadataAlternates } from '~/lib/seo/canonical'; diff --git a/core/app/[locale]/(default)/blog/page.tsx b/core/app/[locale]/(default)/blog/page.tsx index 3de928ec80..44f940a718 100644 --- a/core/app/[locale]/(default)/blog/page.tsx +++ b/core/app/[locale]/(default)/blog/page.tsx @@ -3,9 +3,9 @@ import { notFound } from 'next/navigation'; import { getTranslations, setRequestLocale } from 'next-intl/server'; import { SearchParams } from 'nuqs'; import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/server'; +import { Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; -import { Suspense } from 'react'; import { FeaturedBlogPostList } from '@/vibes/soul/sections/featured-blog-post-list'; import { defaultPageInfo, pageInfoTransformer } from '~/data-transformers/page-info-transformer'; import { getMetadataAlternates } from '~/lib/seo/canonical'; diff --git a/core/app/[locale]/(default)/product/[slug]/page.tsx b/core/app/[locale]/(default)/product/[slug]/page.tsx index a3edc6353f..ca93360d14 100644 --- a/core/app/[locale]/(default)/product/[slug]/page.tsx +++ b/core/app/[locale]/(default)/product/[slug]/page.tsx @@ -3,9 +3,9 @@ import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { SearchParams } from 'nuqs/server'; +import { Suspense } from 'react'; import { Stream, Streamable } from '@/vibes/soul/lib/streamable'; -import { Suspense } from 'react'; import { FeaturedProductCarousel } from '@/vibes/soul/sections/featured-product-carousel'; import { ProductDetail } from '@/vibes/soul/sections/product-detail'; import { auth, getSessionCustomerAccessToken } from '~/auth'; diff --git a/core/app/[locale]/(default)/wishlist/[token]/page.tsx b/core/app/[locale]/(default)/wishlist/[token]/page.tsx index aff60394ea..67e716ab74 100644 --- a/core/app/[locale]/(default)/wishlist/[token]/page.tsx +++ b/core/app/[locale]/(default)/wishlist/[token]/page.tsx @@ -3,8 +3,8 @@ import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getFormatter, getTranslations, setRequestLocale } from 'next-intl/server'; import { SearchParams } from 'nuqs'; -import { Suspense } from 'react'; import { createSearchParamsCache, parseAsInteger, parseAsString } from 'nuqs/server'; +import { Suspense } from 'react'; import { Streamable } from '@/vibes/soul/lib/streamable'; import { CursorPaginationInfo } from '@/vibes/soul/primitives/cursor-pagination'; diff --git a/core/vibes/soul/lib/streamable.tsx b/core/vibes/soul/lib/streamable.tsx index 74c6b116af..684534a2cb 100644 --- a/core/vibes/soul/lib/streamable.tsx +++ b/core/vibes/soul/lib/streamable.tsx @@ -15,7 +15,9 @@ const stableKeys = (function () { return key; } - const keyValue = String(counter++); + const keyValue = String(counter); + + counter += 1; cache.set(obj, keyValue); From b2c790fbcd0b142974ecaa2d0b1b18ed7b5a90e2 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Thu, 5 Mar 2026 14:45:52 -0600 Subject: [PATCH 22/24] fix: wrap footer --- core/app/[locale]/(default)/layout.tsx | 4 +++- core/client/correlation-id.ts | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 core/client/correlation-id.ts diff --git a/core/app/[locale]/(default)/layout.tsx b/core/app/[locale]/(default)/layout.tsx index 3d9713f5fe..b50a5560de 100644 --- a/core/app/[locale]/(default)/layout.tsx +++ b/core/app/[locale]/(default)/layout.tsx @@ -21,7 +21,9 @@ export default async function DefaultLayout({ params, children }: Props) {
{children}
-