diff --git a/.nvmrc b/.nvmrc index b6a7d89c6..3c032078a 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16 +18 diff --git a/app/api/revalidate/route.ts b/app/api/revalidate/route.ts index 94ddfff9b..47af2a4a4 100644 --- a/app/api/revalidate/route.ts +++ b/app/api/revalidate/route.ts @@ -1,37 +1,8 @@ -import { TAGS } from 'lib/constants'; -import { revalidateTag } from 'next/cache'; -import { headers } from 'next/headers'; +import { revalidate } from 'lib/shopify'; import { NextRequest, NextResponse } from 'next/server'; export const runtime = 'edge'; -// We always need to respond with a 200 status code to Shopify, -// otherwise it will continue to retry the request. -export async function POST(req: NextRequest): Promise { - const collectionWebhooks = ['collections/create', 'collections/delete', 'collections/update']; - const productWebhooks = ['products/create', 'products/delete', 'products/update']; - const topic = headers().get('x-shopify-topic') || 'unknown'; - const secret = req.nextUrl.searchParams.get('secret'); - const isCollectionUpdate = collectionWebhooks.includes(topic); - const isProductUpdate = productWebhooks.includes(topic); - - if (!secret || secret !== process.env.SHOPIFY_REVALIDATION_SECRET) { - console.error('Invalid revalidation secret.'); - return NextResponse.json({ status: 200 }); - } - - if (!isCollectionUpdate && !isProductUpdate) { - // We don't need to revalidate anything for any other topics. - return NextResponse.json({ status: 200 }); - } - - if (isCollectionUpdate) { - revalidateTag(TAGS.collections); - } - - if (isProductUpdate) { - revalidateTag(TAGS.products); - } - - return NextResponse.json({ status: 200, revalidated: true, now: Date.now() }); +export async function POST(req: NextRequest): Promise { + return revalidate(req); } diff --git a/app/error.tsx b/app/error.tsx index 3e2b40b1a..e0a7416a3 100644 --- a/app/error.tsx +++ b/app/error.tsx @@ -2,9 +2,18 @@ export default function Error({ reset }: { reset: () => void }) { return ( -
-

Something went wrong.

- +
+

Oh no!

+

+ There was an issue with our storefront. This could be a temporary issue, please try your + action again. +

+
); } diff --git a/app/favicon.ico b/app/favicon.ico index c4826c947..dc7d8431e 100644 Binary files a/app/favicon.ico and b/app/favicon.ico differ diff --git a/app/layout.tsx b/app/layout.tsx index 2674f79fc..7256fb488 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -4,10 +4,14 @@ import { ReactNode, Suspense } from 'react'; import './globals.css'; const { TWITTER_CREATOR, TWITTER_SITE, SITE_NAME } = process.env; +const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL + ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}` + : 'http://localhost:3000'; export const metadata = { + metadataBase: new URL(baseUrl), title: { - default: SITE_NAME, + default: SITE_NAME!, template: `%s | ${SITE_NAME}` }, robots: { diff --git a/app/product/[handle]/page.tsx b/app/product/[handle]/page.tsx index 63b205c92..d59423364 100644 --- a/app/product/[handle]/page.tsx +++ b/app/product/[handle]/page.tsx @@ -23,17 +23,17 @@ export async function generateMetadata({ if (!product) return notFound(); const { url, width, height, altText: alt } = product.featuredImage || {}; - const hide = !product.tags.includes(HIDDEN_PRODUCT_TAG); + const indexable = !product.tags.includes(HIDDEN_PRODUCT_TAG); return { title: product.seo.title || product.title, description: product.seo.description || product.description, robots: { - index: hide, - follow: hide, + index: indexable, + follow: indexable, googleBot: { - index: hide, - follow: hide + index: indexable, + follow: indexable } }, openGraph: url @@ -82,8 +82,8 @@ export default async function ProductPage({ params }: { params: { handle: string }} />
-
-
+
+
({ src: image.url, @@ -92,7 +92,7 @@ export default async function ProductPage({ params }: { params: { handle: string />
-
+
@@ -115,14 +115,13 @@ async function RelatedProducts({ id }: { id: string }) { return (

Related Products

-
- {relatedProducts.map((product, i) => { - return ( - +
    + {relatedProducts.map((product) => ( +
  • + - ); - })} -
+ + ))} +
); } diff --git a/app/search/page.tsx b/app/search/page.tsx index 5f4b60c01..2f7a53bd4 100644 --- a/app/search/page.tsx +++ b/app/search/page.tsx @@ -24,7 +24,7 @@ export default async function SearchPage({ return ( <> {searchValue ? ( -

+

{products.length === 0 ? 'There are no products that match ' : `Showing ${products.length} ${resultsText} for `} diff --git a/app/sitemap.ts b/app/sitemap.ts index d8cdfd2ea..46d39669c 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -1,11 +1,16 @@ import { getCollections, getPages, getProducts } from 'lib/shopify'; import { MetadataRoute } from 'next'; +type Route = { + url: string; + lastModified: string; +}; + const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}` : 'http://localhost:3000'; -export default async function sitemap(): Promise>> { +export default async function sitemap(): Promise { const routesMap = [''].map((route) => ({ url: `${baseUrl}${route}`, lastModified: new Date().toISOString() @@ -32,9 +37,13 @@ export default async function sitemap(): Promise -

- {[...products, ...products].map((product, i) => ( - + {carouselProducts.map((product, i) => ( +
  • - - + + + +
  • ))} -
    +
    ); } diff --git a/components/cart/actions.ts b/components/cart/actions.ts index 8188458e2..3fb013194 100644 --- a/components/cart/actions.ts +++ b/components/cart/actions.ts @@ -3,7 +3,7 @@ import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/shopify'; import { cookies } from 'next/headers'; -export const addItem = async (variantId: string | undefined): Promise => { +export const addItem = async (variantId: string | undefined): Promise => { let cartId = cookies().get('cartId')?.value; let cart; @@ -18,25 +18,26 @@ export const addItem = async (variantId: string | undefined): Promise => { +export const removeItem = async (lineId: string): Promise => { const cartId = cookies().get('cartId')?.value; if (!cartId) { - return new Error('Missing cartId'); + return 'Missing cart ID'; } try { await removeFromCart(cartId, [lineId]); } catch (e) { - return new Error('Error removing item', { cause: e }); + return 'Error removing item from cart'; } }; @@ -48,11 +49,11 @@ export const updateItemQuantity = async ({ lineId: string; variantId: string; quantity: number; -}): Promise => { +}): Promise => { const cartId = cookies().get('cartId')?.value; if (!cartId) { - return new Error('Missing cartId'); + return 'Missing cart ID'; } try { await updateCart(cartId, [ @@ -63,6 +64,6 @@ export const updateItemQuantity = async ({ } ]); } catch (e) { - return new Error('Error updating item quantity', { cause: e }); + return 'Error updating item quantity'; } }; diff --git a/components/cart/add-to-cart.tsx b/components/cart/add-to-cart.tsx index d737b6678..f9d21c0fd 100644 --- a/components/cart/add-to-cart.tsx +++ b/components/cart/add-to-cart.tsx @@ -6,7 +6,7 @@ import { addItem } from 'components/cart/actions'; import LoadingDots from 'components/loading-dots'; import { ProductVariant } from 'lib/shopify/types'; import { useRouter, useSearchParams } from 'next/navigation'; -import { useEffect, useState, useTransition } from 'react'; +import { useTransition } from 'react'; export function AddToCart({ variants, @@ -15,21 +15,16 @@ export function AddToCart({ variants: ProductVariant[]; availableForSale: boolean; }) { - const [selectedVariantId, setSelectedVariantId] = useState(undefined); const router = useRouter(); const searchParams = useSearchParams(); const [isPending, startTransition] = useTransition(); - - useEffect(() => { - const variant = variants.find((variant: ProductVariant) => - variant.selectedOptions.every( - (option) => option.value === searchParams.get(option.name.toLowerCase()) - ) - ); - - setSelectedVariantId(variant?.id); - }, [searchParams, variants, setSelectedVariantId]); - + const defaultVariantId = variants.length === 1 ? variants[0]?.id : undefined; + const variant = variants.find((variant: ProductVariant) => + variant.selectedOptions.every( + (option) => option.value === searchParams.get(option.name.toLowerCase()) + ) + ); + const selectedVariantId = variant?.id || defaultVariantId; const title = !availableForSale ? 'Out of stock' : !selectedVariantId @@ -49,8 +44,8 @@ export function AddToCart({ const error = await addItem(selectedVariantId); if (error) { - alert(error); - return; + // Trigger the error boundary in the root error.js + throw new Error(error.toString()); } router.refresh(); diff --git a/components/cart/delete-item-button.tsx b/components/cart/delete-item-button.tsx index f279f178d..605adcf51 100644 --- a/components/cart/delete-item-button.tsx +++ b/components/cart/delete-item-button.tsx @@ -19,8 +19,8 @@ export default function DeleteItemButton({ item }: { item: CartItem }) { const error = await removeItem(item.id); if (error) { - alert(error); - return; + // Trigger the error boundary in the root error.js + throw new Error(error.toString()); } router.refresh(); diff --git a/components/cart/edit-item-quantity-button.tsx b/components/cart/edit-item-quantity-button.tsx index 8b1553f73..e846196ca 100644 --- a/components/cart/edit-item-quantity-button.tsx +++ b/components/cart/edit-item-quantity-button.tsx @@ -32,8 +32,8 @@ export default function EditItemQuantityButton({ }); if (error) { - alert(error); - return; + // Trigger the error boundary in the root error.js + throw new Error(error.toString()); } router.refresh(); diff --git a/components/cart/modal.tsx b/components/cart/modal.tsx index 7c0c67b19..4fbfcc6ad 100644 --- a/components/cart/modal.tsx +++ b/components/cart/modal.tsx @@ -25,7 +25,7 @@ export default function CartModal({ cart }: { cart: Cart | undefined }) { const closeCart = () => setIsOpen(false); useEffect(() => { - // Open cart modal when when quantity changes. + // Open cart modal when quantity changes. if (cart?.totalQuantity !== quantityRef.current) { // But only if it's not already open (quantity also changes when editing items in cart). if (!isOpen) { @@ -111,7 +111,7 @@ export default function CartModal({ cart }: { cart: Cart | undefined }) { >
    {
    -

    +

    {item.quantity}

    diff --git a/components/grid/three-items.tsx b/components/grid/three-items.tsx index 4a680fc36..23b3f8991 100644 --- a/components/grid/three-items.tsx +++ b/components/grid/three-items.tsx @@ -3,17 +3,27 @@ import { getCollectionProducts } from 'lib/shopify'; import type { Product } from 'lib/shopify/types'; import Link from 'next/link'; -function ThreeItemGridItem({ item, size }: { item: Product; size: 'full' | 'half' }) { +function ThreeItemGridItem({ + item, + size, + priority +}: { + item: Product; + size: 'full' | 'half'; + priority?: boolean; +}) { return (
    - + - - +
    + +
    ); diff --git a/components/icons/github.tsx b/components/icons/github.tsx deleted file mode 100644 index e74d90722..000000000 --- a/components/icons/github.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export default function GitHubIcon({ className }: { className?: string }) { - return ( - - - - ); -} diff --git a/components/label.tsx b/components/label.tsx index e49efce40..113afacb0 100644 --- a/components/label.tsx +++ b/components/label.tsx @@ -18,8 +18,8 @@ const Label = ({ 'lg:px-20 lg:pb-[35%]': position === 'center' })} > -
    -

    {title}

    +
    +

    {title}

    { }, [pathname, item.path]); return ( -
  • +
  • - + {SITE_NAME} @@ -40,12 +39,13 @@ export default async function Footer() {
    diff --git a/components/layout/navbar/index.tsx b/components/layout/navbar/index.tsx index 09341c646..2683942c9 100644 --- a/components/layout/navbar/index.tsx +++ b/components/layout/navbar/index.tsx @@ -30,12 +30,12 @@ export default async function Navbar() {
    {menu.length ? ( -
      +
        {menu.map((item: Menu) => (
      • {item.title} diff --git a/components/layout/navbar/mobile-menu.tsx b/components/layout/navbar/mobile-menu.tsx index 05654d9c1..6d798370e 100644 --- a/components/layout/navbar/mobile-menu.tsx +++ b/components/layout/navbar/mobile-menu.tsx @@ -32,8 +32,12 @@ export default function MobileMenu({ menu }: { menu: Menu[] }) { return ( <> - @@ -59,7 +63,11 @@ export default function MobileMenu({ menu }: { menu: Menu[] }) { >
        - @@ -67,14 +75,13 @@ export default function MobileMenu({ menu }: { menu: Menu[] }) {
        {menu.length ? ( -
          +
            {menu.map((item: Menu) => ( -
          • - +
          • + {item.title}
          • diff --git a/components/layout/navbar/search.tsx b/components/layout/navbar/search.tsx index e6d9ce307..c7a410b9d 100644 --- a/components/layout/navbar/search.tsx +++ b/components/layout/navbar/search.tsx @@ -32,7 +32,7 @@ export default function Search() { } return ( -
            + {products.map((product) => ( - + diff --git a/components/layout/search/filter/item.tsx b/components/layout/search/filter/item.tsx index 38777ea48..925d2c204 100644 --- a/components/layout/search/filter/item.tsx +++ b/components/layout/search/filter/item.tsx @@ -52,7 +52,7 @@ function SortFilterItem({ item }: { item: SortFilterItem }) { diff --git a/components/product/gallery.tsx b/components/product/gallery.tsx index 8636a1cc9..eabc500e3 100644 --- a/components/product/gallery.tsx +++ b/components/product/gallery.tsx @@ -2,33 +2,40 @@ import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'; import { GridTileImage } from 'components/grid/tile'; +import { createUrl } from 'lib/utils'; import Image from 'next/image'; -import { useState } from 'react'; +import Link from 'next/link'; +import { usePathname, useSearchParams } from 'next/navigation'; export function Gallery({ images }: { images: { src: string; altText: string }[] }) { - const [currentImageIndex, setCurrentImageIndex] = useState(0); + const pathname = usePathname(); + const searchParams = useSearchParams(); + const imageSearchParam = searchParams.get('image'); + const imageIndex = imageSearchParam ? parseInt(imageSearchParam) : 0; - function handleNavigate(direction: 'next' | 'previous') { - if (direction === 'next') { - setCurrentImageIndex(currentImageIndex + 1 < images.length ? currentImageIndex + 1 : 0); - } else { - setCurrentImageIndex(currentImageIndex === 0 ? images.length - 1 : currentImageIndex - 1); - } - } + const nextSearchParams = new URLSearchParams(searchParams.toString()); + const nextImageIndex = imageIndex + 1 < images.length ? imageIndex + 1 : 0; + nextSearchParams.set('image', nextImageIndex.toString()); + const nextUrl = createUrl(pathname, nextSearchParams); + + const previousSearchParams = new URLSearchParams(searchParams.toString()); + const previousImageIndex = imageIndex === 0 ? images.length - 1 : imageIndex - 1; + previousSearchParams.set('image', previousImageIndex.toString()); + const previousUrl = createUrl(pathname, previousSearchParams); const buttonClassName = - 'h-full px-6 transition-all ease-in-out hover:scale-110 hover:text-black dark:hover:text-white'; + 'h-full px-6 transition-all ease-in-out hover:scale-110 hover:text-black dark:hover:text-white flex items-center justify-center'; return ( -
            -
            - {images[currentImageIndex] && ( + <> +
            + {images[imageIndex] && ( {images[currentImageIndex]?.altText )} @@ -36,49 +43,57 @@ export function Gallery({ images }: { images: { src: string; altText: string }[] {images.length > 1 ? (
            - +
            - +
            ) : null}
            {images.length > 1 ? ( -
            +
              {images.map((image, index) => { - const isActive = index === currentImageIndex; + const isActive = index === imageIndex; + const imageSearchParams = new URLSearchParams(searchParams.toString()); + + imageSearchParams.set('image', index.toString()); + return ( - +
            • + + + +
            • ); })} -
            +
          ) : null} -
  • + ); } diff --git a/lib/shopify/index.ts b/lib/shopify/index.ts index 64b5d24e8..a8804d045 100644 --- a/lib/shopify/index.ts +++ b/lib/shopify/index.ts @@ -1,5 +1,8 @@ import { HIDDEN_PRODUCT_TAG, SHOPIFY_GRAPHQL_API_ENDPOINT, TAGS } from 'lib/constants'; import { isShopifyError } from 'lib/type-guards'; +import { revalidateTag } from 'next/cache'; +import { headers } from 'next/headers'; +import { NextRequest, NextResponse } from 'next/server'; import { addToCartMutation, createCartMutation, @@ -408,3 +411,35 @@ export async function getProducts({ return reshapeProducts(removeEdgesAndNodes(res.body.data.products)); } + +// This is called from `app/api/revalidate.ts` so providers can control revalidation logic. +export async function revalidate(req: NextRequest): Promise { + // We always need to respond with a 200 status code to Shopify, + // otherwise it will continue to retry the request. + const collectionWebhooks = ['collections/create', 'collections/delete', 'collections/update']; + const productWebhooks = ['products/create', 'products/delete', 'products/update']; + const topic = headers().get('x-shopify-topic') || 'unknown'; + const secret = req.nextUrl.searchParams.get('secret'); + const isCollectionUpdate = collectionWebhooks.includes(topic); + const isProductUpdate = productWebhooks.includes(topic); + + if (!secret || secret !== process.env.SHOPIFY_REVALIDATION_SECRET) { + console.error('Invalid revalidation secret.'); + return NextResponse.json({ status: 200 }); + } + + if (!isCollectionUpdate && !isProductUpdate) { + // We don't need to revalidate anything for any other topics. + return NextResponse.json({ status: 200 }); + } + + if (isCollectionUpdate) { + revalidateTag(TAGS.collections); + } + + if (isProductUpdate) { + revalidateTag(TAGS.products); + } + + return NextResponse.json({ status: 200, revalidated: true, now: Date.now() }); +} diff --git a/package.json b/package.json index 6fd83bd41..ced3d26a4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": true, "packageManager": "pnpm@8.2.0", "engines": { - "node": ">=16", + "node": ">=18", "pnpm": ">=7" }, "scripts": { @@ -25,7 +25,7 @@ "@headlessui/react": "^1.7.15", "@heroicons/react": "^2.0.18", "clsx": "^2.0.0", - "next": "13.4.12", + "next": "13.4.13-canary.15", "react": "18.2.0", "react-dom": "18.2.0" }, @@ -43,7 +43,7 @@ "eslint-plugin-unicorn": "^48.0.0", "lint-staged": "^13.2.3", "postcss": "^8.4.27", - "prettier": "^3.0.0", + "prettier": "3.0.1", "prettier-plugin-tailwindcss": "^0.4.1", "tailwindcss": "^3.3.3", "typescript": "5.1.6" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27e9c4375..67dc0e88d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,8 +11,8 @@ dependencies: specifier: ^2.0.0 version: 2.0.0 next: - specifier: 13.4.12 - version: 13.4.12(react-dom@18.2.0)(react@18.2.0) + specifier: 13.4.13-canary.15 + version: 13.4.13-canary.15(react-dom@18.2.0)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -61,11 +61,11 @@ devDependencies: specifier: ^8.4.27 version: 8.4.27 prettier: - specifier: ^3.0.0 - version: 3.0.0 + specifier: 3.0.1 + version: 3.0.1 prettier-plugin-tailwindcss: specifier: ^0.4.1 - version: 0.4.1(prettier@3.0.0) + version: 0.4.1(prettier@3.0.1) tailwindcss: specifier: ^3.3.3 version: 3.3.3 @@ -224,8 +224,8 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /@next/env@13.4.12: - resolution: {integrity: sha512-RmHanbV21saP/6OEPBJ7yJMuys68cIf8OBBWd7+uj40LdpmswVAwe1uzeuFyUsd6SfeITWT3XnQfn6wULeKwDQ==} + /@next/env@13.4.13-canary.15: + resolution: {integrity: sha512-AljMmO5a2uB0ZTDcBVhcfkE7WtdQDfnPg2zz/e6jKjVMRFPSvxaoRoSGUwONIhk9CAPbX9px7bZYom2wbhrTkw==} dev: false /@next/eslint-plugin-next@13.4.12: @@ -234,8 +234,8 @@ packages: glob: 7.1.7 dev: true - /@next/swc-darwin-arm64@13.4.12: - resolution: {integrity: sha512-deUrbCXTMZ6ZhbOoloqecnUeNpUOupi8SE2tx4jPfNS9uyUR9zK4iXBvH65opVcA/9F5I/p8vDXSYbUlbmBjZg==} + /@next/swc-darwin-arm64@13.4.13-canary.15: + resolution: {integrity: sha512-ymE/tPjf5DXIqWxEefkqGX094ZDpKw/0sKb7xmzF0m8Kolac1eqA6ZnCsb1TKXYVQyrGUx/Z0xmxCK4cm2dEdw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -243,8 +243,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64@13.4.12: - resolution: {integrity: sha512-WRvH7RxgRHlC1yb5oG0ZLx8F7uci9AivM5/HGGv9ZyG2Als8Ij64GC3d+mQ5sJhWjusyU6T6V1WKTUoTmOB0zQ==} + /@next/swc-darwin-x64@13.4.13-canary.15: + resolution: {integrity: sha512-B9fCPRjE1t5r1bmivq5fqHvU8mLNX7hkS2zj9arVrZEC7HdOugbSOpmQb5+yr5ZmNKMItQbPDJIATY+ZAiUtww==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -252,8 +252,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu@13.4.12: - resolution: {integrity: sha512-YEKracAWuxp54tKiAvvq73PUs9lok57cc8meYRibTWe/VdPB2vLgkTVWFcw31YDuRXdEhdX0fWS6Q+ESBhnEig==} + /@next/swc-linux-arm64-gnu@13.4.13-canary.15: + resolution: {integrity: sha512-K30IPFxZPtZLs1gqir95oNdCNgmu0awbC7MMLqOu9+wmW+LYjA6M3ltRe2Duy9nZ7JQob1oRl/s7MMbtCuzVAA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -261,8 +261,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl@13.4.12: - resolution: {integrity: sha512-LhJR7/RAjdHJ2Isl2pgc/JaoxNk0KtBgkVpiDJPVExVWA1c6gzY57+3zWuxuyWzTG+fhLZo2Y80pLXgIJv7g3g==} + /@next/swc-linux-arm64-musl@13.4.13-canary.15: + resolution: {integrity: sha512-ClJvWIhvCLXM3iSMet9bqKxyxifN7DGo8+wiV8gwIU+OMWHGNgGtmZ3xXae3R91w8DOLrsREyBN4uGLlgpwRXg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -270,8 +270,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu@13.4.12: - resolution: {integrity: sha512-1DWLL/B9nBNiQRng+1aqs3OaZcxC16Nf+mOnpcrZZSdyKHek3WQh6j/fkbukObgNGwmCoVevLUa/p3UFTTqgqg==} + /@next/swc-linux-x64-gnu@13.4.13-canary.15: + resolution: {integrity: sha512-/B0xaPcdx2HWDC9Bxks3dLIUyu9Falmd7ENRanYizfdihgM+kV2zIQe/5h5zaESKMEltLt2ELPOPCaFU5gOnYA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -279,8 +279,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl@13.4.12: - resolution: {integrity: sha512-kEAJmgYFhp0VL+eRWmUkVxLVunn7oL9Mdue/FS8yzRBVj7Z0AnIrHpTIeIUl1bbdQq1VaoOztnKicAjfkLTRCQ==} + /@next/swc-linux-x64-musl@13.4.13-canary.15: + resolution: {integrity: sha512-YZZlKne+5iwsPe9yN8QP5sfyDN7ybpWTuYukfv6sKL68STuAVqqp4QX2g7a3Fw+LMJiDwyCFJaUDgO9KSLEqDw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -288,8 +288,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc@13.4.12: - resolution: {integrity: sha512-GMLuL/loR6yIIRTnPRY6UGbLL9MBdw2anxkOnANxvLvsml4F0HNIgvnU3Ej4BjbqMTNjD4hcPFdlEow4XHPdZA==} + /@next/swc-win32-arm64-msvc@13.4.13-canary.15: + resolution: {integrity: sha512-nOi9w+E+ajqJuQhcB260AMJERJPYS1K5pL+5Rymyt9VWCZEJZiHTRuaf8y/H7sObZcQKwRVa7C/EWyZjj658XA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -297,8 +297,8 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc@13.4.12: - resolution: {integrity: sha512-PhgNqN2Vnkm7XaMdRmmX0ZSwZXQAtamBVSa9A/V1dfKQCV1rjIZeiy/dbBnVYGdj63ANfsOR/30XpxP71W0eww==} + /@next/swc-win32-ia32-msvc@13.4.13-canary.15: + resolution: {integrity: sha512-EqV5Bt7TmdFWa00KkoEeb5K4uRFrV1BAiwqylsk+d+2U1N2UIad/dTOyTzobjDcZ9uii1EaCVMiTuMfcsGIahw==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -306,8 +306,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc@13.4.12: - resolution: {integrity: sha512-Z+56e/Ljt0bUs+T+jPjhFyxYBcdY2RIq9ELFU+qAMQMteHo7ymbV7CKmlcX59RI9C4YzN8PgMgLyAoi916b5HA==} + /@next/swc-win32-x64-msvc@13.4.13-canary.15: + resolution: {integrity: sha512-hZcZ0vS1eevRTr1JUyDfTYXF36DBEowNZWyzNW8ZrlGMZyQloE9yf/jHoLtutxr2jV6GoHWGGqVSw4exOyjjKw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2241,25 +2241,22 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /next@13.4.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-eHfnru9x6NRmTMcjQp6Nz0J4XH9OubmzOa7CkWL+AUrUxpibub3vWwttjduu9No16dug1kq04hiUUpo7J3m3Xw==} + /next@13.4.13-canary.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-dSOzenhqdjH6fNbSKYZ4PkqmKLOviFSVUd75Csz+zZPoTWmAKR+9waUAttOyRnUgYd/qutt8KXGH+DiU0nmhVA==} engines: {node: '>=16.8.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - fibers: '>= 3.1.0' react: ^18.2.0 react-dom: ^18.2.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': optional: true - fibers: - optional: true sass: optional: true dependencies: - '@next/env': 13.4.12 + '@next/env': 13.4.13-canary.15 '@swc/helpers': 0.5.1 busboy: 1.6.0 caniuse-lite: 1.0.30001517 @@ -2270,15 +2267,15 @@ packages: watchpack: 2.4.0 zod: 3.21.4 optionalDependencies: - '@next/swc-darwin-arm64': 13.4.12 - '@next/swc-darwin-x64': 13.4.12 - '@next/swc-linux-arm64-gnu': 13.4.12 - '@next/swc-linux-arm64-musl': 13.4.12 - '@next/swc-linux-x64-gnu': 13.4.12 - '@next/swc-linux-x64-musl': 13.4.12 - '@next/swc-win32-arm64-msvc': 13.4.12 - '@next/swc-win32-ia32-msvc': 13.4.12 - '@next/swc-win32-x64-msvc': 13.4.12 + '@next/swc-darwin-arm64': 13.4.13-canary.15 + '@next/swc-darwin-x64': 13.4.13-canary.15 + '@next/swc-linux-arm64-gnu': 13.4.13-canary.15 + '@next/swc-linux-arm64-musl': 13.4.13-canary.15 + '@next/swc-linux-x64-gnu': 13.4.13-canary.15 + '@next/swc-linux-x64-musl': 13.4.13-canary.15 + '@next/swc-win32-arm64-msvc': 13.4.13-canary.15 + '@next/swc-win32-ia32-msvc': 13.4.13-canary.15 + '@next/swc-win32-x64-msvc': 13.4.13-canary.15 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -2633,7 +2630,7 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier-plugin-tailwindcss@0.4.1(prettier@3.0.0): + /prettier-plugin-tailwindcss@0.4.1(prettier@3.0.1): resolution: {integrity: sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==} engines: {node: '>=12.17.0'} peerDependencies: @@ -2685,11 +2682,11 @@ packages: prettier-plugin-twig-melody: optional: true dependencies: - prettier: 3.0.0 + prettier: 3.0.1 dev: true - /prettier@3.0.0: - resolution: {integrity: sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==} + /prettier@3.0.1: + resolution: {integrity: sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==} engines: {node: '>=14'} hasBin: true dev: true