diff --git a/apps/web/app/(dashboard)/home/(user)/billing/server-actions.ts b/apps/web/app/(dashboard)/home/(user)/billing/server-actions.ts index bb33cc374..485168c92 100644 --- a/apps/web/app/(dashboard)/home/(user)/billing/server-actions.ts +++ b/apps/web/app/(dashboard)/home/(user)/billing/server-actions.ts @@ -2,25 +2,26 @@ import { redirect } from 'next/navigation'; -import { z } from 'zod'; - +import { enhanceAction } from '@kit/next/actions'; import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client'; import { PersonalAccountCheckoutSchema } from './_lib/schema/personal-account-checkout.schema'; import { UserBillingService } from './_lib/server/user-billing.service'; /** + * @name createPersonalAccountCheckoutSession * @description Creates a checkout session for a personal account. */ -export async function createPersonalAccountCheckoutSession( - params: z.infer, -) { - // parse the parameters - const data = PersonalAccountCheckoutSchema.parse(params); - const service = new UserBillingService(getSupabaseServerActionClient()); +export const createPersonalAccountCheckoutSession = enhanceAction( + async function (data) { + const service = new UserBillingService(getSupabaseServerActionClient()); - return await service.createCheckoutSession(data); -} + return await service.createCheckoutSession(data); + }, + { + schema: PersonalAccountCheckoutSchema, + }, +); /** * @description Creates a billing Portal session for a personal account diff --git a/apps/web/app/(dashboard)/home/(user)/settings/actions.server.ts b/apps/web/app/(dashboard)/home/(user)/settings/actions.server.ts deleted file mode 100644 index e175d3e75..000000000 --- a/apps/web/app/(dashboard)/home/(user)/settings/actions.server.ts +++ /dev/null @@ -1,12 +0,0 @@ -'use server'; - -import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client'; - -/** - * Refreshes the user session on the server when updating the user profile. - */ -export async function refreshSessionAction() { - const supabase = getSupabaseServerActionClient(); - - await supabase.auth.refreshSession(); -} diff --git a/apps/web/app/(dashboard)/home/[account]/_lib/schema/team-billing-portal.schema.ts b/apps/web/app/(dashboard)/home/[account]/_lib/schema/team-billing-portal.schema.ts deleted file mode 100644 index 570b69e4e..000000000 --- a/apps/web/app/(dashboard)/home/[account]/_lib/schema/team-billing-portal.schema.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { z } from 'zod'; - -export const TeamBillingPortalSchema = z.object({ - accountId: z.string().uuid(), - slug: z.string().min(1), -}); diff --git a/apps/web/app/(dashboard)/home/[account]/_lib/schema/team-checkout.schema.ts b/apps/web/app/(dashboard)/home/[account]/_lib/schema/team-billing.schema.ts similarity index 63% rename from apps/web/app/(dashboard)/home/[account]/_lib/schema/team-checkout.schema.ts rename to apps/web/app/(dashboard)/home/[account]/_lib/schema/team-billing.schema.ts index 12c1127ec..3d8f045da 100644 --- a/apps/web/app/(dashboard)/home/[account]/_lib/schema/team-checkout.schema.ts +++ b/apps/web/app/(dashboard)/home/[account]/_lib/schema/team-billing.schema.ts @@ -1,5 +1,10 @@ import { z } from 'zod'; +export const TeamBillingPortalSchema = z.object({ + accountId: z.string().uuid(), + slug: z.string().min(1), +}); + export const TeamCheckoutSchema = z.object({ slug: z.string().min(1), productId: z.string().min(1), diff --git a/apps/web/app/(dashboard)/home/[account]/_lib/server/team-billing.service.ts b/apps/web/app/(dashboard)/home/[account]/_lib/server/team-billing.service.ts index 70043da62..1319c2950 100644 --- a/apps/web/app/(dashboard)/home/[account]/_lib/server/team-billing.service.ts +++ b/apps/web/app/(dashboard)/home/[account]/_lib/server/team-billing.service.ts @@ -14,7 +14,7 @@ import appConfig from '~/config/app.config'; import billingConfig from '~/config/billing.config'; import pathsConfig from '~/config/paths.config'; -import { TeamCheckoutSchema } from '../../_lib/schema/team-checkout.schema'; +import { TeamCheckoutSchema } from '../../_lib/schema/team-billing.schema'; export class TeamBillingService { private readonly namespace = 'billing.team-account'; diff --git a/apps/web/app/(dashboard)/home/[account]/billing/server-actions.ts b/apps/web/app/(dashboard)/home/[account]/billing/server-actions.ts index 676324ee8..1de169330 100644 --- a/apps/web/app/(dashboard)/home/[account]/billing/server-actions.ts +++ b/apps/web/app/(dashboard)/home/[account]/billing/server-actions.ts @@ -6,9 +6,11 @@ import { z } from 'zod'; import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client'; -import { TeamBillingPortalSchema } from '~/(dashboard)/home/[account]/_lib/schema/team-billing-portal.schema'; - -import { TeamCheckoutSchema } from '../_lib/schema/team-checkout.schema'; +// billing imports +import { + TeamBillingPortalSchema, + TeamCheckoutSchema, +} from '../_lib/schema/team-billing.schema'; import { TeamBillingService } from '../_lib/server/team-billing.service'; /** @@ -19,7 +21,6 @@ export async function createTeamAccountCheckoutSession( params: z.infer, ) { const data = TeamCheckoutSchema.parse(params); - const service = new TeamBillingService(getSupabaseServerActionClient()); return service.createCheckout(data); @@ -32,7 +33,6 @@ export async function createTeamAccountCheckoutSession( */ export async function createBillingPortalSession(formData: FormData) { const params = TeamBillingPortalSchema.parse(Object.fromEntries(formData)); - const service = new TeamBillingService(getSupabaseServerActionClient()); // get url to billing portal diff --git a/apps/web/components/root-providers.tsx b/apps/web/components/root-providers.tsx index e9950b153..546fbd61a 100644 --- a/apps/web/components/root-providers.tsx +++ b/apps/web/components/root-providers.tsx @@ -4,7 +4,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'; import { ThemeProvider } from 'next-themes'; -import { CaptchaProvider, CaptchaTokenSetter } from '@kit/auth/captcha'; +import { CaptchaProvider, CaptchaTokenSetter } from '@kit/auth/captcha/client'; import { I18nProvider } from '@kit/i18n/provider'; import { AuthChangeListener } from '@kit/supabase/components/auth-change-listener'; diff --git a/apps/web/config/auth.config.ts b/apps/web/config/auth.config.ts index 70c4d4246..62a9961b3 100644 --- a/apps/web/config/auth.config.ts +++ b/apps/web/config/auth.config.ts @@ -20,7 +20,7 @@ const AuthConfigSchema = z.object({ const authConfig = AuthConfigSchema.parse({ // NB: This is a public key, so it's safe to expose. // Copy the value from the Supabase Dashboard. - captchaTokenSiteKey: process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY ?? '', + captchaTokenSiteKey: process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY, // NB: Enable the providers below in the Supabase Console // in your production project diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 9007a83f9..910641b88 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -17,6 +17,7 @@ const INTERNAL_PACKAGES = [ '@kit/database-webhooks', '@kit/cms', '@kit/monitoring', + '@kit/next' ]; /** @type {import('next').NextConfig} */ diff --git a/apps/web/package.json b/apps/web/package.json index 375adbc1b..b74214080 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -28,6 +28,7 @@ "@kit/i18n": "workspace:^", "@kit/mailers": "workspace:^", "@kit/monitoring": "workspace:^", + "@kit/next": "workspace:^", "@kit/shared": "workspace:^", "@kit/supabase": "workspace:^", "@kit/team-accounts": "workspace:^", @@ -44,7 +45,7 @@ "i18next": "^23.10.1", "i18next-resources-to-backend": "^1.2.0", "lucide-react": "^0.363.0", - "next": "14.2.0-canary.60", + "next": "14.2.0-canary.61", "next-sitemap": "^4.2.3", "next-themes": "0.3.0", "react": "18.2.0", diff --git a/packages/features/auth/package.json b/packages/features/auth/package.json index 056336783..92c60df5b 100644 --- a/packages/features/auth/package.json +++ b/packages/features/auth/package.json @@ -14,7 +14,8 @@ "./password-reset": "./src/password-reset.ts", "./shared": "./src/shared.ts", "./mfa": "./src/mfa.ts", - "./captcha": "./src/components/captcha/index.ts" + "./captcha/client": "./src/captcha/client/index.ts", + "./captcha/server": "./src/captcha/server/index.ts" }, "devDependencies": { "@hookform/resolvers": "^3.3.4", diff --git a/packages/features/auth/src/components/captcha/captcha-provider.tsx b/packages/features/auth/src/captcha/client/captcha-provider.tsx similarity index 100% rename from packages/features/auth/src/components/captcha/captcha-provider.tsx rename to packages/features/auth/src/captcha/client/captcha-provider.tsx diff --git a/packages/features/auth/src/components/captcha/captchaTokenSetter.tsx b/packages/features/auth/src/captcha/client/captchaTokenSetter.tsx similarity index 100% rename from packages/features/auth/src/components/captcha/captchaTokenSetter.tsx rename to packages/features/auth/src/captcha/client/captchaTokenSetter.tsx diff --git a/packages/features/auth/src/components/captcha/index.ts b/packages/features/auth/src/captcha/client/index.ts similarity index 100% rename from packages/features/auth/src/components/captcha/index.ts rename to packages/features/auth/src/captcha/client/index.ts diff --git a/packages/features/auth/src/components/captcha/use-captcha-token.ts b/packages/features/auth/src/captcha/client/use-captcha-token.ts similarity index 100% rename from packages/features/auth/src/components/captcha/use-captcha-token.ts rename to packages/features/auth/src/captcha/client/use-captcha-token.ts diff --git a/packages/features/auth/src/captcha/server/index.ts b/packages/features/auth/src/captcha/server/index.ts new file mode 100644 index 000000000..0a083a55f --- /dev/null +++ b/packages/features/auth/src/captcha/server/index.ts @@ -0,0 +1 @@ +export * from './verify-captcha'; diff --git a/packages/features/auth/src/captcha/server/verify-captcha.tsx b/packages/features/auth/src/captcha/server/verify-captcha.tsx new file mode 100644 index 000000000..21cb27b21 --- /dev/null +++ b/packages/features/auth/src/captcha/server/verify-captcha.tsx @@ -0,0 +1,30 @@ +import 'server-only'; + +const verifyEndpoint = + 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; + +const secret = process.env.CAPTCHA_SECRET_TOKEN; + +/** + * Verify the CAPTCHA token with the CAPTCHA service + * @param token + */ +export async function verifyCaptchaToken(token: string) { + if (!secret) { + throw new Error('CAPTCHA_SECRET_TOKEN is not set'); + } + + const res = await fetch(verifyEndpoint, { + method: 'POST', + body: `secret=${encodeURIComponent(secret)}&response=${encodeURIComponent(token)}`, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + }); + + const data = await res.json(); + + if (!data.success) { + throw new Error('Invalid CAPTCHA token'); + } +} diff --git a/packages/features/auth/src/components/sign-up-methods-container.tsx b/packages/features/auth/src/components/sign-up-methods-container.tsx index 36ac4ca85..55ed0c3fe 100644 --- a/packages/features/auth/src/components/sign-up-methods-container.tsx +++ b/packages/features/auth/src/components/sign-up-methods-container.tsx @@ -8,7 +8,7 @@ import { If } from '@kit/ui/if'; import { Separator } from '@kit/ui/separator'; import { Trans } from '@kit/ui/trans'; -import { useCaptchaToken } from './captcha'; +import { useCaptchaToken } from '../captcha/client'; import { MagicLinkAuthContainer } from './magic-link-auth-container'; import { OauthProviders } from './oauth-providers'; import { EmailPasswordSignUpContainer } from './password-sign-up-container'; diff --git a/packages/next/package.json b/packages/next/package.json new file mode 100644 index 000000000..e20007b4b --- /dev/null +++ b/packages/next/package.json @@ -0,0 +1,41 @@ +{ + "name": "@kit/next", + "private": true, + "version": "0.1.0", + "scripts": { + "clean": "git clean -xdf .turbo node_modules", + "format": "prettier --check \"**/*.{ts,tsx}\"", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "prettier": "@kit/prettier-config", + "exports": { + "./actions": "./src/actions/index.ts" + }, + "peerDependencies": { + "@kit/auth": "workspace:*", + "@kit/supabase": "workspace:*" + }, + "devDependencies": { + "@kit/auth": "*", + "@kit/eslint-config": "workspace:*", + "@kit/prettier-config": "workspace:*", + "@kit/supabase": "*", + "@kit/tailwind-config": "workspace:*", + "@kit/tsconfig": "workspace:*" + }, + "eslintConfig": { + "root": true, + "extends": [ + "@kit/eslint-config/base", + "@kit/eslint-config/react" + ] + }, + "typesVersions": { + "*": { + "*": [ + "src/*" + ] + } + } +} diff --git a/packages/next/src/actions/index.ts b/packages/next/src/actions/index.ts new file mode 100644 index 000000000..3c07d4d25 --- /dev/null +++ b/packages/next/src/actions/index.ts @@ -0,0 +1,67 @@ +import { redirect } from 'next/navigation'; + +import type { User } from '@supabase/supabase-js'; + +import { z } from 'zod'; + +import { verifyCaptchaToken } from '@kit/auth/captcha/server'; +import { requireUser } from '@kit/supabase/require-user'; +import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client'; + +const parseFactory = + (schema: T) => + (data: unknown): z.infer => { + try { + return schema.parse(data); + } catch (err) { + console.error(err); + + // handle error + throw new Error(`Invalid data: ${err}`); + } + }; + +/** + * + * @name enhanceAction + * @description Enhance an action with captcha, schema and auth checks + */ +export function enhanceAction< + Args, + Schema extends z.ZodType, z.ZodTypeDef>, + Response, +>( + fn: (params: z.infer, user: User) => Response, + config: { + captcha?: boolean; + schema: Schema; + }, +) { + return async ( + params: z.infer & { + captchaToken?: string; + }, + ) => { + // verify the user is authenticated if required + const auth = await requireUser(getSupabaseServerActionClient()); + + // If the user is not authenticated, redirect to the specified URL. + if (!auth.data) { + redirect(auth.redirectTo); + } + + // verify the captcha token if required + if (config.captcha) { + const token = z.string().min(1).parse(params.captchaToken); + + await verifyCaptchaToken(token); + } + + // validate the schema + const parsed = parseFactory(config.schema); + const data = parsed(params); + + // pass the data to the action + return fn(data, auth.data); + }; +} diff --git a/packages/next/tsconfig.json b/packages/next/tsconfig.json new file mode 100644 index 000000000..c4697e934 --- /dev/null +++ b/packages/next/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@kit/tsconfig/base.json", + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" + }, + "include": ["*.ts", "src"], + "exclude": ["node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c86c43659..a4a3e0619 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: '@kit/monitoring': specifier: workspace:^ version: link:../../packages/monitoring + '@kit/next': + specifier: workspace:^ + version: link:../../packages/next '@kit/shared': specifier: workspace:^ version: link:../../packages/shared @@ -100,7 +103,7 @@ importers: version: 5.28.6(react@18.2.0) '@tanstack/react-query-next-experimental': specifier: ^5.28.14 - version: 5.28.14(@tanstack/react-query@5.28.6)(next@14.2.0-canary.60)(react@18.2.0) + version: 5.28.14(@tanstack/react-query@5.28.6)(next@14.2.0-canary.61)(react@18.2.0) '@tanstack/react-table': specifier: ^8.15.3 version: 8.15.3(react-dom@18.2.0)(react@18.2.0) @@ -109,7 +112,7 @@ importers: version: 3.6.0 edge-csrf: specifier: ^1.0.9 - version: 1.0.9(next@14.2.0-canary.60) + version: 1.0.9(next@14.2.0-canary.61) i18next: specifier: ^23.10.1 version: 23.10.1 @@ -120,11 +123,11 @@ importers: specifier: ^0.363.0 version: 0.363.0(react@18.2.0) next: - specifier: 14.2.0-canary.60 - version: 14.2.0-canary.60(react-dom@18.2.0)(react@18.2.0) + specifier: 14.2.0-canary.61 + version: 14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0) next-sitemap: specifier: ^4.2.3 - version: 4.2.3(next@14.2.0-canary.60) + version: 4.2.3(next@14.2.0-canary.61) next-themes: specifier: 0.3.0 version: 0.3.0(react-dom@18.2.0)(react@18.2.0) @@ -761,6 +764,27 @@ importers: specifier: workspace:* version: link:../../../tooling/typescript + packages/next: + devDependencies: + '@kit/auth': + specifier: '*' + version: link:../features/auth + '@kit/eslint-config': + specifier: workspace:* + version: link:../../tooling/eslint + '@kit/prettier-config': + specifier: workspace:* + version: link:../../tooling/prettier + '@kit/supabase': + specifier: '*' + version: link:../supabase + '@kit/tailwind-config': + specifier: workspace:* + version: link:../../tooling/tailwind + '@kit/tsconfig': + specifier: workspace:* + version: link:../../tooling/typescript + packages/shared: dependencies: pino: @@ -2278,8 +2302,8 @@ packages: resolution: {integrity: sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==} dev: false - /@next/env@14.2.0-canary.60: - resolution: {integrity: sha512-JHZFqtJYmYZqDEojGJxZo6UpfHJdWv2gTDYaXBdugiOR17jlOfh0lvydwloelY5AybgBI+gcOMDBlA4NvHqwzQ==} + /@next/env@14.2.0-canary.61: + resolution: {integrity: sha512-Ueqse8kdwaoebGrpSo60M4/cjFaMJEE7BMsKZufYwZDTlE0qXw7N4GsdVpUZzJG00sXf6CoTnCU1lCTPrUMC4g==} dev: false /@next/eslint-plugin-next@14.1.4: @@ -2306,8 +2330,8 @@ packages: dev: false optional: true - /@next/swc-darwin-arm64@14.2.0-canary.60: - resolution: {integrity: sha512-qnlZH711F+GSqJjU1pa6GZVYPMgNko3LxnWa856HgSJgIeKhwAK3Mvr4d6OJDzKykoPXK/pCel4ulNpVQeMk9A==} + /@next/swc-darwin-arm64@14.2.0-canary.61: + resolution: {integrity: sha512-mMlp2/hvtaBbCY5qYhuvAqX9Z/aFC+Rgme4FjFSxq2C3TC/mL3G4fVG/TVl7bqjikKCxSvJgiWXRwvhIaqGktw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -2333,8 +2357,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64@14.2.0-canary.60: - resolution: {integrity: sha512-F0oF2O9Ytwrinq7+++qF3JQui1V7RZE7u83mkOIY638i3kMCke/EkXUsjdrg8BLudoZaDq2t77ynjbTk2GWszA==} + /@next/swc-darwin-x64@14.2.0-canary.61: + resolution: {integrity: sha512-4bEjO0WK6keRi972eAY1AfvTXOQRHnM59klNqnUh5zfalbi7VkEdluhYAZOop2NycCHjF+m8p+ytYtrF1uCO1Q==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -2360,8 +2384,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu@14.2.0-canary.60: - resolution: {integrity: sha512-1jUgAbKaOXb6Jt6CKsoAskUeWz0FilvP/I/czJl6huYkemff4kUxECv6hjvxmBUzHgxoYv0bzJCwRAIXut0fJw==} + /@next/swc-linux-arm64-gnu@14.2.0-canary.61: + resolution: {integrity: sha512-wIXc3EdxrETlL2XwlGlLQkMU9godhNSMAXxiJotd/mhN3K4iKajPahAStvFxY2Zwc/on2IBa0NpUGpzDONNt9A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2387,8 +2411,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl@14.2.0-canary.60: - resolution: {integrity: sha512-ekK7wdHWGk63Qre2L7uO0vFlm9O34qQn9XusZLp+de7ZgE/iOsXWg6dJ82OSTUUHbyYJuqAtid1nbUM5ajV1rQ==} + /@next/swc-linux-arm64-musl@14.2.0-canary.61: + resolution: {integrity: sha512-95aMF55sq2N6+5iLEqxCfz7ccYMBURQ8D0KYmcq+rMJTE5z/qvxEToSJWAbV4jGyd2Eq/vXjPdR1rFytv2FnOw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2414,8 +2438,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu@14.2.0-canary.60: - resolution: {integrity: sha512-9LsH0lyrx2bxLqGMyvh7szVB5Wz+rYfqp0kFBqYecURrm3wsTUfVhXRonVYY2y0nkZFN0K9SxjpR1x0Vs35oaA==} + /@next/swc-linux-x64-gnu@14.2.0-canary.61: + resolution: {integrity: sha512-LWG5OC9hNSCYtDb+7MQcIjE1PO70Sho+ZJkqJnmLxJ08Atp/nJQBo9nAMjORdcO5Nz+hPNVY5vmrY+5Fl5kadw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2441,8 +2465,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl@14.2.0-canary.60: - resolution: {integrity: sha512-0I7vfnkpENB58RvlGiwG2kAb7PXKTsvvACvMq8/daOs+kYJrmMRrR2AQQ/dVEBckWwSewfBSb74lxcu0uyLRBA==} + /@next/swc-linux-x64-musl@14.2.0-canary.61: + resolution: {integrity: sha512-EjOXbSmDTPVi8xkOix4/WYJM6OUert+lfBtdUJBRba+oGiRw/mheih8FliFZKFOmQbPYj67A9z/QCus2ZDnfSw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2468,8 +2492,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc@14.2.0-canary.60: - resolution: {integrity: sha512-50RYKSsZn0cLk+4VRtd0jfgAGheFiBAuk/ZKacrkZgnnqQCvuf1HYJq019b+kpHMQYAYGZMNky90Tjwp5RnX/w==} + /@next/swc-win32-arm64-msvc@14.2.0-canary.61: + resolution: {integrity: sha512-TK8oV4ozzUGWAwvZp/0SBsNgAUhrUFLWCMSXsFHz+YMRjHg7nT0KdK8BYh2Ln4Qt0jjDTUHbI1jaQKxmSMEMmA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -2495,8 +2519,8 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc@14.2.0-canary.60: - resolution: {integrity: sha512-EiUtA0ylWn21Jd27XbFvu5Rm/QEpH5Twt4uZ9GlguKEqpdduIjzZpLHgPJvp+3m/kNbwlPEcT48UZ4DDEIU16g==} + /@next/swc-win32-ia32-msvc@14.2.0-canary.61: + resolution: {integrity: sha512-i0iWCehuLKDOfVbQ6MEKG9v0lfcJU0DPWkYINFSi6p3fkFobI/+7DVT3KvYH5VVng/+opx+pA6cesV5eyQnBtw==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -2522,8 +2546,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc@14.2.0-canary.60: - resolution: {integrity: sha512-z5KZYtUrSdAYkPVUcYpb7VvXLN6up/Dk7EONdMi17KaRJtBAeuSZHpf0y93Z3/yW+eajXGBQ1ZoNRtQ0cAZJgw==} + /@next/swc-win32-x64-msvc@14.2.0-canary.61: + resolution: {integrity: sha512-WB0UjpWcu+oXQOMFDTHDZWKcL2jiXeQfN+1RRkb0x7ZjVxvA/O66vOJE08fLSu7rdymLiGXxX+AKlGFq1Tpisg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -5014,7 +5038,7 @@ packages: /@tanstack/query-core@5.28.6: resolution: {integrity: sha512-hnhotV+DnQtvtR3jPvbQMPNMW4KEK0J4k7c609zJ8muiNknm+yoDyMHmxTWM5ZnlZpsz0zOxYFr+mzRJNHWJsA==} - /@tanstack/react-query-next-experimental@5.28.14(@tanstack/react-query@5.28.6)(next@14.2.0-canary.60)(react@18.2.0): + /@tanstack/react-query-next-experimental@5.28.14(@tanstack/react-query@5.28.6)(next@14.2.0-canary.61)(react@18.2.0): resolution: {integrity: sha512-gGHx3uJkZNYYpFNFk8eEo96ssiFE2OmYA49wszHxHrtO5nL7kzRcnJF8SALGpqSEjo5D3fLMH24MrhbBsO0sig==} peerDependencies: '@tanstack/react-query': ^5.28.14 @@ -5022,7 +5046,7 @@ packages: react: ^18.0.0 dependencies: '@tanstack/react-query': 5.28.6(react@18.2.0) - next: 14.2.0-canary.60(react-dom@18.2.0)(react@18.2.0) + next: 14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 dev: false @@ -6834,12 +6858,12 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - /edge-csrf@1.0.9(next@14.2.0-canary.60): + /edge-csrf@1.0.9(next@14.2.0-canary.61): resolution: {integrity: sha512-3F89YTh42UDdISr3s9AEcgJDLi4ysgjGfnybzF0LuZGaG2W31h1ZwgWwEQBLMj04lAklcP4XHZYi7vk9o8zcbg==} peerDependencies: next: ^13.0.0 || ^14.0.0 dependencies: - next: 14.2.0-canary.60(react-dom@18.2.0)(react@18.2.0) + next: 14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0) dev: false /editorconfig@1.0.4: @@ -9624,7 +9648,7 @@ packages: - supports-color dev: false - /next-sitemap@4.2.3(next@14.2.0-canary.60): + /next-sitemap@4.2.3(next@14.2.0-canary.61): resolution: {integrity: sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==} engines: {node: '>=14.18'} hasBin: true @@ -9635,7 +9659,7 @@ packages: '@next/env': 13.5.6 fast-glob: 3.3.2 minimist: 1.2.8 - next: 14.2.0-canary.60(react-dom@18.2.0)(react@18.2.0) + next: 14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0) dev: false /next-themes@0.3.0(react-dom@18.2.0)(react@18.2.0): @@ -9727,8 +9751,8 @@ packages: - babel-plugin-macros dev: false - /next@14.2.0-canary.60(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-8PTu/wB8pd24wZnFb5bpHQulXnGQl+8yjc3D1QK17j268obdf+kPQmo/L4x3EQhCOkK7tasA/c5y9R9EMvbntQ==} + /next@14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UbdoNkGX04TO0Q0N3k7fmiNCliE1yihVBHd/nwg2zMnpjB6dGU3r1UNgCBpfUUlrs1t19FAWazfVQANOOfBT4w==} engines: {node: '>=18.17.0'} hasBin: true peerDependencies: @@ -9745,7 +9769,7 @@ packages: sass: optional: true dependencies: - '@next/env': 14.2.0-canary.60 + '@next/env': 14.2.0-canary.61 '@swc/helpers': 0.5.5 busboy: 1.6.0 caniuse-lite: 1.0.30001600 @@ -9755,15 +9779,15 @@ packages: react-dom: 18.2.0(react@18.2.0) styled-jsx: 5.1.1(react@18.2.0) optionalDependencies: - '@next/swc-darwin-arm64': 14.2.0-canary.60 - '@next/swc-darwin-x64': 14.2.0-canary.60 - '@next/swc-linux-arm64-gnu': 14.2.0-canary.60 - '@next/swc-linux-arm64-musl': 14.2.0-canary.60 - '@next/swc-linux-x64-gnu': 14.2.0-canary.60 - '@next/swc-linux-x64-musl': 14.2.0-canary.60 - '@next/swc-win32-arm64-msvc': 14.2.0-canary.60 - '@next/swc-win32-ia32-msvc': 14.2.0-canary.60 - '@next/swc-win32-x64-msvc': 14.2.0-canary.60 + '@next/swc-darwin-arm64': 14.2.0-canary.61 + '@next/swc-darwin-x64': 14.2.0-canary.61 + '@next/swc-linux-arm64-gnu': 14.2.0-canary.61 + '@next/swc-linux-arm64-musl': 14.2.0-canary.61 + '@next/swc-linux-x64-gnu': 14.2.0-canary.61 + '@next/swc-linux-x64-musl': 14.2.0-canary.61 + '@next/swc-win32-arm64-msvc': 14.2.0-canary.61 + '@next/swc-win32-ia32-msvc': 14.2.0-canary.61 + '@next/swc-win32-x64-msvc': 14.2.0-canary.61 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros