From 0002ac6255dc5af53900194bda81e0d5c9b1cfb7 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Sun, 7 Apr 2024 12:47:29 +0800 Subject: [PATCH] Refactor billing imports, reorganize package scripts and improve action structure Deleted unnecessary schema files and reorganized their imports into more logical order. Modified the package script structure to align more accurately with standard conventions. Also refactored the team-billing.service file to improve action structure, making it easier to understand and edit. Furthermore, upgraded various dependencies, reflecting their new versions in the lockfile. --- .../home/(user)/billing/server-actions.ts | 21 ++-- .../home/(user)/settings/actions.server.ts | 12 -- .../_lib/schema/team-billing-portal.schema.ts | 6 - ...ckout.schema.ts => team-billing.schema.ts} | 5 + .../_lib/server/team-billing.service.ts | 2 +- .../home/[account]/billing/server-actions.ts | 10 +- apps/web/components/root-providers.tsx | 2 +- apps/web/config/auth.config.ts | 2 +- apps/web/next.config.mjs | 1 + apps/web/package.json | 3 +- packages/features/auth/package.json | 3 +- .../client}/captcha-provider.tsx | 0 .../client}/captchaTokenSetter.tsx | 0 .../captcha => captcha/client}/index.ts | 0 .../client}/use-captcha-token.ts | 0 .../features/auth/src/captcha/server/index.ts | 1 + .../src/captcha/server/verify-captcha.tsx | 30 +++++ .../components/sign-up-methods-container.tsx | 2 +- packages/next/package.json | 41 +++++++ packages/next/src/actions/index.ts | 67 +++++++++++ packages/next/tsconfig.json | 8 ++ pnpm-lock.yaml | 110 +++++++++++------- 22 files changed, 244 insertions(+), 82 deletions(-) delete mode 100644 apps/web/app/(dashboard)/home/(user)/settings/actions.server.ts delete mode 100644 apps/web/app/(dashboard)/home/[account]/_lib/schema/team-billing-portal.schema.ts rename apps/web/app/(dashboard)/home/[account]/_lib/schema/{team-checkout.schema.ts => team-billing.schema.ts} (63%) rename packages/features/auth/src/{components/captcha => captcha/client}/captcha-provider.tsx (100%) rename packages/features/auth/src/{components/captcha => captcha/client}/captchaTokenSetter.tsx (100%) rename packages/features/auth/src/{components/captcha => captcha/client}/index.ts (100%) rename packages/features/auth/src/{components/captcha => captcha/client}/use-captcha-token.ts (100%) create mode 100644 packages/features/auth/src/captcha/server/index.ts create mode 100644 packages/features/auth/src/captcha/server/verify-captcha.tsx create mode 100644 packages/next/package.json create mode 100644 packages/next/src/actions/index.ts create mode 100644 packages/next/tsconfig.json 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