From 16a25e02e7278ab6c7b64e4b93b0eac3bfd92a87 Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:54:55 +0900 Subject: [PATCH 01/11] =?UTF-8?q?chore:=20Node=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=EC=9D=84=2024.20.0=EC=9C=BC=EB=A1=9C=20=EC=98=AC=EB=A6=B0?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 87e33794..89270f7b 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v24.19.0 \ No newline at end of file +v24.20.0 \ No newline at end of file From 3396f81bdd4eed33ec56979181fe2b294ea56bcb Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:55:21 +0900 Subject: [PATCH 02/11] =?UTF-8?q?chore:=20tsconfig=EC=9D=98=20include=20?= =?UTF-8?q?=EC=88=9C=EC=84=9C=EC=99=80=20exclude=EB=A5=BC=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) --- tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 494fc71c..ac71f082 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,6 +30,6 @@ "@/*": ["./src/*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mts", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"], - "exclude": ["node_modules", ".backup"] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts", "**/*.mts"], + "exclude": ["node_modules"] } From 326caa927cd1f9a206ac8d8912c376f8b31af2bf Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:55:24 +0900 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=EB=B3=B8=EB=AC=B8=20=EC=A4=84=20?= =?UTF-8?q?=EB=86=92=EC=9D=B4=EB=A5=BC=20=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B8=20=EA=B0=92=EC=9C=BC=EB=A1=9C=20=EB=90=98?= =?UTF-8?q?=EB=8F=8C=EB=A6=B0=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 토큰을 tokens.css로 모으던 2026-08-25 작업에서 --leading-prose가 1.85에서 1.8로 바뀌었다. 커밋 메시지에 근거가 없고 디자인 정본은 1.85다. 글 본문 전체의 줄 간격이 걸리는 값이라 되돌린다. Co-Authored-By: Claude Opus 5 (1M context) --- src/app/styles/globals.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/styles/globals.css b/src/app/styles/globals.css index 362c0287..fd5eaac0 100644 --- a/src/app/styles/globals.css +++ b/src/app/styles/globals.css @@ -121,7 +121,7 @@ --leading-tight: 1.45; --leading-snug: 1.55; --leading-body: 1.75; - --leading-prose: 1.8; + --leading-prose: 1.85; --blur-header: 10px; From 108aa3f35212b476bc64a02d901f999bf6e33fe5 Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:55:35 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20OG=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=20=ED=81=AC=EA=B8=B0=EB=A5=BC=20=EC=83=81=EC=88=98=20=ED=95=98?= =?UTF-8?q?=EB=82=98=EB=A1=9C=20=EB=AA=A8=EC=9D=80=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1200x630이 og 라우트와 buildMetadata, 루트 layout 세 곳에 각각 박혀 있었다. OG_IMAGE_SIZE 하나를 보게 바꾼다. buildMetadata의 image가 문자열 외에 치수를 아는 객체도 받는다. 썸네일은 크기를 모르지만 우리가 만든 기본 이미지는 알기 때문이다. Co-Authored-By: Claude Opus 5 (1M context) --- src/shared/config/site.ts | 10 ++++++++++ src/shared/seo/build-metadata.ts | 25 +++++++++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/shared/config/site.ts b/src/shared/config/site.ts index 24dc1f98..8e2cfb3a 100644 --- a/src/shared/config/site.ts +++ b/src/shared/config/site.ts @@ -31,6 +31,16 @@ export const siteMetadata = { export const siteHostname = new URL(siteMetadata.url).hostname; +export const OG_IMAGE_SIZE = { + width: 1200, + height: 630 +} as const; + +export const OG_DEFAULT_IMAGE = { + url: "/images/og-default.jpg", + ...OG_IMAGE_SIZE +} as const; + type SocialLinkConfig = { label: string; href: string; diff --git a/src/shared/seo/build-metadata.ts b/src/shared/seo/build-metadata.ts index a376896c..9c1333db 100644 --- a/src/shared/seo/build-metadata.ts +++ b/src/shared/seo/build-metadata.ts @@ -1,12 +1,14 @@ import type { Metadata } from "next"; -import { siteMetadata } from "@/shared/config/site"; +import { OG_IMAGE_SIZE, siteMetadata } from "@/shared/config/site"; + +type OgImageInput = string | { url: string; width: number; height: number }; type BuildMetadataInput = { title: string; description: string; path: string; - image?: string; + image?: OgImageInput; type?: "website" | "article"; publishedAt?: string; modifiedAt?: string; @@ -16,11 +18,18 @@ type BuildMetadataInput = { follow?: boolean; }; +function resolveOgImage(image: OgImageInput | undefined, title: string) { + if (typeof image === "string") { + return { url: image, alt: title }; + } + + const resolved = image ?? { url: `/og?title=${encodeURIComponent(title)}`, ...OG_IMAGE_SIZE }; + + return { ...resolved, alt: title }; +} + export function buildMetadata(input: BuildMetadataInput) { - const ogImage = input.image || `/og?title=${encodeURIComponent(input.title)}`; - const ogImageDescriptor = input.image - ? { url: ogImage, alt: input.title } - : { url: ogImage, width: 1200, height: 630, alt: input.title }; + const ogImage = resolveOgImage(input.image, input.title); const ogCommon = { url: input.path, @@ -28,7 +37,7 @@ export function buildMetadata(input: BuildMetadataInput) { locale: siteMetadata.locale, title: input.title, description: input.description, - images: [ogImageDescriptor] + images: [ogImage] }; const openGraph: Metadata["openGraph"] = @@ -60,7 +69,7 @@ export function buildMetadata(input: BuildMetadataInput) { card: "summary_large_image", title: input.title, description: input.description, - images: [{ url: ogImage, alt: input.title }] + images: [{ url: ogImage.url, alt: input.title }] } }; From ac3bab8be53d3396071beb30197b22d2c2741429 Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:55:39 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=EA=B3=B5=EC=9C=A0=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EC=93=B8=20OG=20=EB=B0=B0=EA=B2=BD?= =?UTF-8?q?=EA=B3=BC=20=EA=B8=B0=EB=B3=B8=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EB=84=A3=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인이 준 자산 둘이 코드에 반영돼 있지 않았다. 배경은 Satori가 제목을 얹을 바탕이고 기본 이미지는 그대로 나가는 완성본이다. 둘 다 사이트 다크 테마와 같은 톤으로 다시 그렸다. Co-Authored-By: Claude Opus 5 (1M context) --- public/images/og-default.jpg | Bin 0 -> 38646 bytes src/shared/assets/images/og-background.jpg | Bin 0 -> 17399 bytes src/shared/config/brand.ts | 7 ++++--- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 public/images/og-default.jpg create mode 100644 src/shared/assets/images/og-background.jpg diff --git a/public/images/og-default.jpg b/public/images/og-default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cbbbb6e6bb0561919fcad43c2aaa41918c051028 GIT binary patch literal 38646 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 lirK{=g|yU#G=4JZU2)(7G@k$352Owv9z|* zA<`gbWO*8GIFu4(S&Ug`X3fCDvItE~l)b?d`s|`z)Jbe6K&6NzU2bcka9Q zyt{jTd+zVt_wL0P@Q=uEogu@3C<>vqREVWQk%E+n30g&k z-7Fg@9b$xf8lk;~i1pe$Ml>&^H{lwOW~`Lgn)G9(MQiq$l@ZHyDSsIrMM+tv;*#PW zrs8MrNxbiVl$4s0$@0Au5z1Pj=;sK3t$#miWiOf4wZGm-eF1-tG%C83J;qQ`h}KYy zhQepiBJwK~lpw-o-6gk9B*s_4|?rvum9uf`@U7aqx4FYd-f4Q* z_Fi-Ahi&a2o%r~ZlV5y!=Bu+`pZn%~caNjj*>|CTVCbixFa9z-;<|MC+SvHSE6;8^_LpDZqctQLd7;Uhp=t70F+^Ce5Knkf zctt6Q>Q=#|6QKv1X31NvR4CQ51^+<8@)10M<}nlrCPssjkvrDKSzL&-=-_jE3>e%+ z0Bb6L)m`~Vj&RKFVs1IlLDO-E@-S+^C^y2Z(JD(p?Wqxrdec2BWdT<=ymShq$!w3x zf=&RFT!<4GJCpw}DyYPEw-z$U?K6j%T^ZaBfQev8(G2bZz@z{r+A!GR)|Rz|IUBi? zsJ_D9Q5349w_Y(!+DumU38CJ+c(AS5xW@v`01F9|*}`D~?sZ24xyvDUCjch$kQB|} zJ_6X0^Y#Ppn}aNmwuBgwF)pDk-$a@CN~?maSz_1#O?N07{Oxok5R4pxu>)XIh()yF zr`r%=GM?`7)9pxC^TfuKAYJoBmcpX%2%z#TAEcp8+)+DJ{>Oljx%?s^NI3-A3xJ8_ zCq*;Z34lofO0?mptPy4HVFUGPC1`ZiaJ|W%GJnufT(mU+P63VCf`KAa-Ed%XIZSQ` zz(mrKqWP(AxXbq0S&Wk1%_}|1MH}@?<4<*B)V$xL%vz2c51YYg+U8YY!ovf&2r&V{ z0KsqvGXsBn8wP1uP8xOqU{cbrXv2_26NoTbPn?|Y(3#G0cUnXN*%B3Xm@He?d`BiR z7qf>e8^-i2boAqiBsW#3*SRat*<4oj%D)?%W5$y^rvl0wMrJJgEN~?t1d%ZJ#>xWn zR3-%Sx}3b;1%Qb;TZ(4LPPY(O({IM*EhXr3+^5dhucXZ9>N`w>ZEy-`%oYq3c`6eO z#3YB9dH^sfge2PV`~4uoWZiJ|x`SKW@{4?zSk+^^*3r+Atw&WB)IfF{Svhko*?VNu zLE{_-fh>y#0&UBo?LGiZq+}_Y-}?p;CX2T1Zhsh(a)x9#048N9iZ=Y>07RIqA?YB1 z*%BQ2N3Ci>+vp1Yy!MbHbjY&%UW3sb%UQq8J_wC-7zDB&q5;~LL)%UOOr&Hfn!){l E0$Q-Y;Q#;t literal 0 HcmV?d00001 diff --git a/src/shared/config/brand.ts b/src/shared/config/brand.ts index 2b8c784f..37001341 100644 --- a/src/shared/config/brand.ts +++ b/src/shared/config/brand.ts @@ -1,8 +1,9 @@ -import { readFileSync } from "node:fs"; import { join } from "node:path"; +import { fileToDataUri } from "@/shared/lib/fileToDataUri"; + const IMAGE_DIR = join(process.cwd(), "src", "shared", "assets", "images"); -const LOGO_MARK_WHITE = readFileSync(join(IMAGE_DIR, "logo-mark-white.png")); +export const LOGO_MARK_WHITE_DATA_URI = fileToDataUri(join(IMAGE_DIR, "logo-mark-white.png")); -export const LOGO_MARK_WHITE_DATA_URI = `data:image/png;base64,${LOGO_MARK_WHITE.toString("base64")}`; +export const OG_BACKGROUND_DATA_URI = fileToDataUri(join(IMAGE_DIR, "og-background.jpg")); From 88bdef70e2f30c65f709eb5f6345352b78290f0e Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:55:52 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=EA=B3=B5=EC=9C=A0=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=EC=97=90=EC=84=9C=20=EB=B8=8C=EB=9E=9C=EB=93=9C=20?= =?UTF-8?q?=ED=91=9C=EA=B8=B0=20=EC=A4=91=EB=B3=B5=EC=9D=84=20=EA=B1=B7?= =?UTF-8?q?=EC=96=B4=EB=82=B8=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 카카오톡과 링크드인은 이미지 아래에 제목과 도메인을 자기가 다시 그린다. 그런데 카드 안에도 같은 것이 들어 있어 한 화면에서 brand 표기가 여섯 번 반복됐다. 위쪽 chan9yu.dev와 아래쪽 chan9yu.dev는 글자까지 같았다. 위쪽에 로고 심볼 하나, 가운데 제목, 아래쪽 도메인만 남긴다. 배경은 CSS 그라데이션 대신 디자인 자산을 쓰고 글자색은 사이트 다크 토큰에 맞춘다. 홈은 Satori를 거치지 않고 완성본을 쓴다. Co-Authored-By: Claude Opus 5 (1M context) --- src/app/api-routes/og-image.tsx | 58 +++++++++++++-------------------- src/app/ui/RootLayout.tsx | 8 ++--- src/pages/home/ui/HomePage.tsx | 4 ++- 3 files changed, 29 insertions(+), 41 deletions(-) diff --git a/src/app/api-routes/og-image.tsx b/src/app/api-routes/og-image.tsx index 13128253..2c80a3c0 100644 --- a/src/app/api-routes/og-image.tsx +++ b/src/app/api-routes/og-image.tsx @@ -1,12 +1,12 @@ import { ImageResponse } from "next/og"; -import { LOGO_MARK_WHITE_DATA_URI } from "@/shared/config/brand"; +import { LOGO_MARK_WHITE_DATA_URI, OG_BACKGROUND_DATA_URI } from "@/shared/config/brand"; import { loadPretendardFonts, PRETENDARD_FAMILY } from "@/shared/config/fonts"; -import { siteHostname, siteMetadata } from "@/shared/config/site"; +import { OG_IMAGE_SIZE, siteHostname, siteMetadata } from "@/shared/config/site"; const MAX_TITLE = 80; const MAX_TAG = 32; -const MARK_SIZE = 28; +const MARK_SIZE = 44; const CACHE_HEADERS = { "Cache-Control": "public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800" }; @@ -50,8 +50,6 @@ export function renderOgImage(req: Request) { } } - const eyebrow = tag ? `#${tag}` : `${siteMetadata.name}.dev`; - return new ImageResponse(
-
- {eyebrow} +
+ {tag ? ( + + {`#${tag}`} + + ) : ( + + )}
-
- {siteHostname} -
- - {siteMetadata.name} -
-
+
{siteHostname}
, { - width: 1200, - height: 630, + ...OG_IMAGE_SIZE, fonts: loadPretendardFonts(), headers: CACHE_HEADERS } diff --git a/src/app/ui/RootLayout.tsx b/src/app/ui/RootLayout.tsx index 704cabcb..26114268 100644 --- a/src/app/ui/RootLayout.tsx +++ b/src/app/ui/RootLayout.tsx @@ -10,7 +10,7 @@ import { Providers } from "@/app/providers"; import { getPublicPosts } from "@/entities/post/index.server"; import { SearchTrigger } from "@/features/search"; import { ThemeSwitcher } from "@/features/theme"; -import { getSiteUrl, siteMetadata } from "@/shared/config/site"; +import { getSiteUrl, OG_DEFAULT_IMAGE, siteMetadata } from "@/shared/config/site"; import { buildWebSiteJsonLd, JsonLdScript } from "@/shared/seo"; import { ScrollReset } from "@/shared/ui/ScrollReset"; import { ScrollToTop } from "@/shared/ui/ScrollToTop"; @@ -18,8 +18,6 @@ import { Footer } from "@/widgets/footer"; import { Header } from "@/widgets/header"; import { MobileMenu } from "@/widgets/mobile-menu"; -const ROOT_OG_IMAGE = `/og?title=${encodeURIComponent(siteMetadata.name)}`; - const googleSiteVerification = process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION?.trim(); const naverSiteVerification = process.env.NEXT_PUBLIC_NAVER_SITE_VERIFICATION?.trim(); @@ -60,13 +58,13 @@ export const rootMetadata: Metadata = { url: "/", title: siteMetadata.title, description: siteMetadata.description, - images: [{ url: ROOT_OG_IMAGE, width: 1200, height: 630, alt: siteMetadata.title }] + images: [{ ...OG_DEFAULT_IMAGE, alt: siteMetadata.title }] }, twitter: { card: "summary_large_image", title: siteMetadata.title, description: siteMetadata.description, - images: [ROOT_OG_IMAGE] + images: [OG_DEFAULT_IMAGE.url] }, icons: { icon: [ diff --git a/src/pages/home/ui/HomePage.tsx b/src/pages/home/ui/HomePage.tsx index 6160247a..6b2d3f85 100644 --- a/src/pages/home/ui/HomePage.tsx +++ b/src/pages/home/ui/HomePage.tsx @@ -5,6 +5,7 @@ import Link from "next/link"; import { getPublicPosts, getTrendingPosts, resolvePostThumbnails } from "@/entities/post/index.server"; import { getTrendingSeries } from "@/entities/series"; import { getTrendingTags } from "@/entities/tag"; +import { OG_DEFAULT_IMAGE } from "@/shared/config/site"; import { buildMetadata } from "@/shared/seo"; import { Container } from "@/shared/ui/Container"; import { RecentPostsList } from "@/widgets/post-list"; @@ -20,7 +21,8 @@ export const metadata: Metadata = buildMetadata({ title: "chan9yu | 프론트엔드 개발 블로그", description: "프론트엔드 엔지니어 chan9yu의 기술 블로그. React 19, TypeScript, Next.js App Router 실무 경험과 WebRTC, 웹 성능 최적화 등 다양한 주제를 깊이 있게 다루며 최신 학습 내용을 정리해 공유합니다.", - path: "/" + path: "/", + image: OG_DEFAULT_IMAGE }); const RECENT_POSTS_LIMIT = 6; From 7685c9f5beb13ffdc5d6512b95e51c15bb25abfb Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:55:56 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20=EC=8D=B8=EB=84=A4=EC=9D=BC=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EA=B8=80=EC=9D=98=20=EB=B1=83=EC=A7=80?= =?UTF-8?q?=EC=97=90=20placeholder=EB=A5=BC=20=EB=84=A3=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인이 준 자산 둘이 놀고 있었고 그 자리에는 단색 박스가 있었다. 자산을 brand.ts가 아니라 별도 모듈에 둔다. brand.ts는 og 라우트가 쓰는데, 한곳에 모으면 두 라우트가 서로 안 쓰는 이미지까지 모듈 로드 시점에 읽는다. Co-Authored-By: Claude Opus 5 (1M context) --- src/app/api-routes/badge-card.tsx | 40 ++++-------------- .../assets/images/badge-placeholder-dark.jpg | Bin 0 -> 9021 bytes .../assets/images/badge-placeholder-light.jpg | Bin 0 -> 8291 bytes src/shared/config/badge-assets.ts | 10 +++++ 4 files changed, 18 insertions(+), 32 deletions(-) create mode 100644 src/shared/assets/images/badge-placeholder-dark.jpg create mode 100644 src/shared/assets/images/badge-placeholder-light.jpg create mode 100644 src/shared/config/badge-assets.ts diff --git a/src/app/api-routes/badge-card.tsx b/src/app/api-routes/badge-card.tsx index fec547c4..7c7c4154 100644 --- a/src/app/api-routes/badge-card.tsx +++ b/src/app/api-routes/badge-card.tsx @@ -9,15 +9,12 @@ import { isBadgeTheme, parseBadgeIndex } from "@/shared/config/badge"; -import { LOGO_MARK_WHITE_DATA_URI } from "@/shared/config/brand"; +import { BADGE_PLACEHOLDER_DATA_URI } from "@/shared/config/badge-assets"; import { loadPretendardFonts, PRETENDARD_FAMILY } from "@/shared/config/fonts"; -import { siteHostname } from "@/shared/config/site"; import { formatDate } from "@/shared/lib/format/formatDate"; import { badgeIndices } from "./badge-redirect"; -const MARK_SIZE = 42; - export function generateBadgeCardParams() { return BADGE_THEMES.flatMap((theme) => badgeIndices().map((index) => ({ index: String(index), theme }))); } @@ -50,34 +47,13 @@ export async function renderBadgeCard( }} >
- {imageDataUri ? ( - - ) : ( -
- - {siteHostname} -
- )} +
6#>%3m)k8{q$3^OqA`OG}?dFC_k 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 nQ&ttTd3qrfJ}$Bii}w3bFv;*HsWBnM>T`(sqjP literal 0 HcmV?d00001 diff --git a/src/shared/config/badge-assets.ts b/src/shared/config/badge-assets.ts new file mode 100644 index 00000000..4f26760c --- /dev/null +++ b/src/shared/config/badge-assets.ts @@ -0,0 +1,10 @@ +import { join } from "node:path"; + +import { fileToDataUri } from "@/shared/lib/fileToDataUri"; + +const IMAGE_DIR = join(process.cwd(), "src", "shared", "assets", "images"); + +export const BADGE_PLACEHOLDER_DATA_URI = { + dark: fileToDataUri(join(IMAGE_DIR, "badge-placeholder-dark.jpg")), + light: fileToDataUri(join(IMAGE_DIR, "badge-placeholder-light.jpg")) +} as const; From 03f42466dccb93a1674c8025488cc0b72e2abd19 Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:56:07 +0900 Subject: [PATCH 08/11] =?UTF-8?q?chore:=20=EC=9D=98=EC=A1=B4=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EC=B5=9C=EC=8B=A0=EC=9C=BC=EB=A1=9C=20=EC=98=AC?= =?UTF-8?q?=EB=A6=AC=EA=B3=A0=20=EC=8B=A4=ED=96=89=20=ED=99=98=EA=B2=BD=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=EC=9D=84=20=EA=B3=A0=EC=A0=95=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit next 16.3.3, zod 4.5.2, lucide-react 1.37.0 등 열 개를 올린다. 모든 항목에 ^ prefix를 붙인다. TypeScript 7과 ESLint 10은 올리지 않는다. typescript-eslint가 TS 7을 명시적으로 거부하고, ESLint 10에서는 eslint-config-next가 끌고 오는 eslint-plugin-react가 크래시한다. 각각 6.x와 9.x 최신을 유지한다. Co-Authored-By: Claude Opus 5 (1M context) --- package.json | 30 +- pnpm-lock.yaml | 760 ++++++++++++++++++++++++------------------------- 2 files changed, 395 insertions(+), 395 deletions(-) diff --git a/package.json b/package.json index b2f11ab7..436b0dc7 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,10 @@ "license": "MIT", "author": "chan9yu ", "private": true, - "packageManager": "pnpm@11.22.0", + "packageManager": "pnpm@11.24.0", "engines": { - "node": ">=24", - "pnpm": ">=11" + "node": "24.x", + "pnpm": "11.x" }, "scripts": { "dev": "next dev --port 3100", @@ -40,13 +40,13 @@ }, "dependencies": { "@shikijs/rehype": "^4.4.3", - "@upstash/redis": "^1.38.2", + "@upstash/redis": "^1.38.3", "@vercel/analytics": "^2.0.1", "@vercel/speed-insights": "^2.0.0", "clsx": "^2.1.1", "fuse.js": "^7.5.0", - "lucide-react": "^1.32.0", - "next": "^16.3.1", + "lucide-react": "^1.37.0", + "next": "^16.3.3", "next-mdx-remote": "^6.0.0", "next-themes": "^0.4.6", "react": "^19.2.8", @@ -58,31 +58,31 @@ "tailwind-merge": "^3.6.0", "vfile": "^6.0.3", "vfile-matter": "^5.0.1", - "zod": "^4.4.3" + "zod": "^4.5.2" }, "devDependencies": { - "@feature-sliced/steiger-plugin": "0.7.0", + "@feature-sliced/steiger-plugin": "^0.7.0", "@playwright/test": "^1.62.1", "@svgr/webpack": "^8.1.0", "@tailwindcss/postcss": "^4.3.3", "@testing-library/jest-dom": "^7.0.1", - "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.5", - "@types/node": "^26.2.0", + "@testing-library/react": "^16.3.3", + "@testing-library/user-event": "^14.6.6", + "@types/node": "^26.4.0", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", + "@types/react-dom": "^19.2.5", "@vitest/coverage-v8": "^4.1.11", "babel-plugin-react-compiler": "^1.0.0", "eslint": "^9.39.5", - "eslint-config-next": "^16.3.1", + "eslint-config-next": "^16.3.3", "eslint-config-prettier": "^10.1.8", "eslint-plugin-simple-import-sort": "^14.0.0", "jsdom": "^30.0.1", - "lefthook": "^2.1.10", + "lefthook": "^2.1.12", "msw": "^2.15.0", "prettier": "^3.9.6", "prettier-plugin-tailwindcss": "^0.8.1", - "steiger": "0.6.0", + "steiger": "^0.6.0", "tailwindcss": "^4.3.3", "typescript": "^6.0.3", "vitest": "^4.1.11" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cbf01173..441aa595 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,14 +12,14 @@ importers: specifier: ^4.4.3 version: 4.4.3 '@upstash/redis': - specifier: ^1.38.2 - version: 1.38.2 + specifier: ^1.38.3 + version: 1.38.3 '@vercel/analytics': specifier: ^2.0.1 - version: 2.0.1(next@16.3.1(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.2.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) + version: 2.0.1(next@16.3.3(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.4.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) '@vercel/speed-insights': specifier: ^2.0.0 - version: 2.0.0(next@16.3.1(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.2.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) + version: 2.0.0(next@16.3.3(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.4.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -27,11 +27,11 @@ importers: specifier: ^7.5.0 version: 7.5.0 lucide-react: - specifier: ^1.32.0 - version: 1.32.0(react@19.2.8) + specifier: ^1.37.0 + version: 1.37.0(react@19.2.8) next: - specifier: ^16.3.1 - version: 16.3.1(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.2.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^16.3.3 + version: 16.3.3(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.4.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) next-mdx-remote: specifier: ^6.0.0 version: 6.0.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) @@ -66,11 +66,11 @@ importers: specifier: ^5.0.1 version: 5.0.1 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: ^4.5.2 + version: 4.5.2 devDependencies: '@feature-sliced/steiger-plugin': - specifier: 0.7.0 + specifier: ^0.7.0 version: 0.7.0(typescript@6.0.3) '@playwright/test': specifier: ^1.62.1 @@ -85,20 +85,20 @@ importers: specifier: ^7.0.1 version: 7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11) '@testing-library/react': - specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^16.3.3 + version: 16.3.3(@testing-library/dom@10.4.1)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@testing-library/user-event': - specifier: ^14.6.5 - version: 14.6.5(@testing-library/dom@10.4.1) + specifier: ^14.6.6 + version: 14.6.6(@testing-library/dom@10.4.1) '@types/node': - specifier: ^26.2.0 - version: 26.2.0 + specifier: ^26.4.0 + version: 26.4.0 '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitest/coverage-v8': specifier: ^4.1.11 version: 4.1.11(vitest@4.1.11) @@ -109,8 +109,8 @@ importers: specifier: ^9.39.5 version: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) eslint-config-next: - specifier: ^16.3.1 - version: 16.3.1(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + specifier: ^16.3.3 + version: 16.3.3(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) eslint-config-prettier: specifier: ^10.1.8 version: 10.1.8(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0)) @@ -121,11 +121,11 @@ importers: specifier: ^30.0.1 version: 30.0.1 lefthook: - specifier: ^2.1.10 - version: 2.1.10 + specifier: ^2.1.12 + version: 2.1.12 msw: specifier: ^2.15.0 - version: 2.15.0(@types/node@26.2.0)(typescript@6.0.3) + version: 2.15.0(@types/node@26.4.0)(typescript@6.0.3) prettier: specifier: ^3.9.6 version: 3.9.6 @@ -133,7 +133,7 @@ importers: specifier: ^0.8.1 version: 0.8.1(prettier@3.9.6) steiger: - specifier: 0.6.0 + specifier: ^0.6.0 version: 0.6.0(typescript@6.0.3) tailwindcss: specifier: ^4.3.3 @@ -143,7 +143,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.11 - version: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(msw@2.15.0(@types/node@26.2.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(msw@2.15.0(@types/node@26.4.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) packages: @@ -779,8 +779,8 @@ packages: '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/runtime@1.11.2': - resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} @@ -868,160 +868,160 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.35.3': - resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + '@img/sharp-darwin-arm64@0.35.4': + resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.35.3': - resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + '@img/sharp-darwin-x64@0.35.4': + resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==} engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-freebsd-wasm32@0.35.3': - resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + '@img/sharp-freebsd-wasm32@0.35.4': + resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==} engines: {node: '>=20.9.0'} os: [freebsd] - '@img/sharp-libvips-darwin-arm64@1.3.2': - resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} + '@img/sharp-libvips-darwin-arm64@1.3.3': + resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.3.2': - resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} + '@img/sharp-libvips-darwin-x64@1.3.3': + resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.3.2': - resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} + '@img/sharp-libvips-linux-arm64@1.3.3': + resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.3.2': - resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} + '@img/sharp-libvips-linux-arm@1.3.3': + resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.3.2': - resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} + '@img/sharp-libvips-linux-ppc64@1.3.3': + resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.3.2': - resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} + '@img/sharp-libvips-linux-riscv64@1.3.3': + resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.3.2': - resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} + '@img/sharp-libvips-linux-s390x@1.3.3': + resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.3.2': - resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} + '@img/sharp-libvips-linux-x64@1.3.3': + resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.3.2': - resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': + resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.3.2': - resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} + '@img/sharp-libvips-linuxmusl-x64@1.3.3': + resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.35.3': - resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + '@img/sharp-linux-arm64@0.35.4': + resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.35.3': - resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + '@img/sharp-linux-arm@0.35.4': + resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==} engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.35.3': - resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + '@img/sharp-linux-ppc64@0.35.4': + resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==} engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-riscv64@0.35.3': - resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + '@img/sharp-linux-riscv64@0.35.4': + resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==} engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.35.3': - resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + '@img/sharp-linux-s390x@0.35.4': + resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==} engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.35.3': - resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + '@img/sharp-linux-x64@0.35.4': + resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.35.3': - resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + '@img/sharp-linuxmusl-arm64@0.35.4': + resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.35.3': - resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + '@img/sharp-linuxmusl-x64@0.35.4': + resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.35.3': - resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + '@img/sharp-wasm32@0.35.4': + resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==} engines: {node: '>=20.9.0'} - '@img/sharp-webcontainers-wasm32@0.35.3': - resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + '@img/sharp-webcontainers-wasm32@0.35.4': + resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==} engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.35.3': - resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + '@img/sharp-win32-arm64@0.35.4': + resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.35.3': - resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + '@img/sharp-win32-ia32@0.35.4': + resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==} engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.35.3': - resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + '@img/sharp-win32-x64@0.35.4': + resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==} engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -1097,60 +1097,60 @@ packages: '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 - '@next/env@16.3.1': - resolution: {integrity: sha512-35G3xwkQUb2oETSDjFXGrVugknoayLFBh7vSE+yAcl9IP2zT9wyGwq7297AYHR11kJld807t5f8AJBs6WBzXsQ==} + '@next/env@16.3.3': + resolution: {integrity: sha512-U2eYQRwXj+dsqxV79zFqExDdatnNY/ZWc2nsJU1p/OgT7fd3dXwlF6OjYaFQCfMoeTA19PWq+wVmYgimVA+V+g==} - '@next/eslint-plugin-next@16.3.1': - resolution: {integrity: sha512-B4SznlXwVpaLDa7Tbi6zLuueria2d/PmFDhXyDymPGrk2r1n/RMJmcn5FZq1L64k+Jsyte1lKvOr7lP9Xo80mQ==} + '@next/eslint-plugin-next@16.3.3': + resolution: {integrity: sha512-pbEh30vvjKpDoTAmo1v3q2uM4JUi8QaEBpbmjWvGfoec2jLghy/WNtvzAT0bk+Ik9oz6etjt4YjXEk4BQnicCw==} - '@next/swc-darwin-arm64@16.3.1': - resolution: {integrity: sha512-ABMIu2zQ7cnNIHm5ivKGwZwUrm0pAai3yiJ/gK/rF1c1VP9UOnj7XECbMKFdVKp9I9eMYq9NoDs1WXOoowxzJw==} + '@next/swc-darwin-arm64@16.3.3': + resolution: {integrity: sha512-8Hiv32QJPwdV6KYJ8meR9SBA061tQqnIKTJDocvOXlEQqib0xMFpzArosuffFUUc0sslbh7QQ8a3Yey1QV8EIw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.3.1': - resolution: {integrity: sha512-gNG21e/UnrroeScbY/QndUEdl0mF1FRibW7BBeYUz/5ABCepjqDdEdgr592vpzMtCn/m7FTjYq3TN4TpyDnutw==} + '@next/swc-darwin-x64@16.3.3': + resolution: {integrity: sha512-A1lgKgwVchRYmSe467zdwhxT9040dd8lH+o65sL5Jet8fjB4kegw/rDyPIpYVRb6jAqwXFOJpjIXJLxQKLiE3A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.3.1': - resolution: {integrity: sha512-6B6Lw016iwNUQuaJoraMMTLh6TwHzFUtxipSScD1F3YyymcrRWkobodRS2ftIOkF5vrs4zNlyUrTC5YZQ9Lz5w==} + '@next/swc-linux-arm64-gnu@16.3.3': + resolution: {integrity: sha512-bf0FIssMFueU2dm7vQEWWxk0c8UjKTdW0yzuh0sQsD8pf1+KCLDdaqhYZNMYGmXwEOiHAUzgBKudovIlcvvBjg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@16.3.1': - resolution: {integrity: sha512-JUiPXZKK9wOhjf4MgDiH29GZLxfqOesbLtHq2pDxwH/WwscTRV2ToymnOTh1egzaZf0ueUf8T2+CeYTGHjW0Iw==} + '@next/swc-linux-arm64-musl@16.3.3': + resolution: {integrity: sha512-W7viwCk9JY/cAkdz/A273rd5bb3RgT/IHwR7Upv90tunjBWNtAAhGhoecHh+teRNRSinuAFmE+l7fwZ4YKkrXg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@16.3.1': - resolution: {integrity: sha512-Uog9jsrmIRIL/lfvIp9htmskSNC7JcQsMVucXL2V2YY1y/D9IUN3LPEafqy0zRJ2cIU1SQ0V6F6TlffQ+pLAGg==} + '@next/swc-linux-x64-gnu@16.3.3': + resolution: {integrity: sha512-0W46zw1N3ODpI6n0GeivHvvob1pooozgZVqy65k0mh4/7vr+FbY9+WpHzNVXjHipJf/A3FDheBG19H1s5A25rA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@16.3.1': - resolution: {integrity: sha512-6yy3FT13KgUFOj5H8bl8w/6nKiJwHIvbtwh1V+1acsu+7y4tJjnemSa6mhsh53BeoVrlozE+fMgZhXH46WmjMA==} + '@next/swc-linux-x64-musl@16.3.3': + resolution: {integrity: sha512-H4mBso8ZTMBPtdT0PN0pBx2ayTvQuTuvS6qT13d77yVFJXAPCxkyIhLTmdMaGTJs0krQYI/qpzdHijCeihXhbg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@16.3.1': - resolution: {integrity: sha512-iOoN1QecUoGNZik536U/vtK43YwgyrCsGIkth52yIkl612n+0C9MjSnJbQAikISpb+WYRooBVhaDlUW7iZoKog==} + '@next/swc-win32-arm64-msvc@16.3.3': + resolution: {integrity: sha512-cTMUJpcEGmeywofCUfhR+rSsoE33+rVPnPEYNTNdLNlsOeEg/vktOsKUSTb28vUGqD2jkm4Zaskcwn7OCI6FQg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.3.1': - resolution: {integrity: sha512-d/k+PpAriUPaeMJJOG7HUSdqfEX46FEPWU1p3/nm2ACmXhj9hFEWdFODUBIpkuijXYkfL90qZzTqVPRp4BW/hw==} + '@next/swc-win32-x64-msvc@16.3.3': + resolution: {integrity: sha512-2VR4cTBzHXaBjnGsuH6GyJjENzQOmHeAh11uY1iUhjm3j5dEUrVJuUj+VL78jaGi/Dik8xS76zEj18BsFhlVZQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1516,8 +1516,8 @@ packages: vitest: optional: true - '@testing-library/react@16.3.2': - resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + '@testing-library/react@16.3.3': + resolution: {integrity: sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==} engines: {node: '>=18'} peerDependencies: '@testing-library/dom': ^10.0.0 @@ -1531,8 +1531,8 @@ packages: '@types/react-dom': optional: true - '@testing-library/user-event@14.6.5': - resolution: {integrity: sha512-FhqjldLTpteueBaKflhNFlMT3+PM0O5fiBUivht6b9CZ1eesJyy7+g3Jr7XwJzt/Hip3ZG5hWwK1MX1FuDiE4w==} + '@testing-library/user-event@14.6.6': + resolution: {integrity: sha512-Jbs9FpkkIDw8FgSc6kOVsOv8JuuqGAL7J4X1oot77JxAoDlkNn2GRkd0aYRVuQ+pVQAiHWVkE4rX/dkF5fBiCw==} engines: {node: '>=12', npm: '>=6'} peerDependencies: '@testing-library/dom': '>=7.21.4' @@ -1576,11 +1576,11 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@26.2.0': - resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} + '@types/node@26.4.0': + resolution: {integrity: sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==} - '@types/react-dom@19.2.4': - resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} + '@types/react-dom@19.2.5': + resolution: {integrity: sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==} peerDependencies: '@types/react': ^19.2.0 @@ -1599,63 +1599,63 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@typescript-eslint/eslint-plugin@8.67.0': - resolution: {integrity: sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==} + '@typescript-eslint/eslint-plugin@8.68.0': + resolution: {integrity: sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.67.0 + '@typescript-eslint/parser': ^8.68.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.67.0': - resolution: {integrity: sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==} + '@typescript-eslint/parser@8.68.0': + resolution: {integrity: sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==} 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.1.0' - '@typescript-eslint/project-service@8.67.0': - resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==} + '@typescript-eslint/project-service@8.68.0': + resolution: {integrity: sha512-5GQtWZCXFcFYux955pvoS02WLc49pXNlvIxocKjS0clvwo3in1RdlzVKyiqQH9vE5AKWFLTaUgeQkOrTS+0Qxw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.67.0': - resolution: {integrity: sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==} + '@typescript-eslint/scope-manager@8.68.0': + resolution: {integrity: sha512-T5eXpcaJNg8bhjHJ8Rjp68Vq/QBteYtTKY8TZqVNPaUbuz0f6jI9t6aDkylwvalpAB9XTTFeFOjrjXAZ3YvmVA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.67.0': - resolution: {integrity: sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==} + '@typescript-eslint/tsconfig-utils@8.68.0': + resolution: {integrity: sha512-F7zrGQfiJHojPwi8vhxZQC1tWtJzvL74cK/nqri2lk8YUXvYaYwl263xOJ69jDWPUk1hmcdoayFwk9lX09npVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.67.0': - resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==} + '@typescript-eslint/type-utils@8.68.0': + resolution: {integrity: sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==} 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.1.0' - '@typescript-eslint/types@8.67.0': - resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==} + '@typescript-eslint/types@8.68.0': + resolution: {integrity: sha512-9RnpsGJjrAllCMefGVVsImJM24YurhC0Q1h4UbvivtvOqXmR/vEJge2OoE++z9m6hyg8T1Q8t5SNT6tHSbrxcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.67.0': - resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==} + '@typescript-eslint/typescript-estree@8.68.0': + resolution: {integrity: sha512-OKKsD0tYmoNiU5PW2zehO1yO56jYOm1ShYlxon/Z0SJNidAkdVg86eg9ruRuoXf8xfnuWZGbwDsStkoXbZtIIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.67.0': - resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==} + '@typescript-eslint/utils@8.68.0': + resolution: {integrity: sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==} 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.1.0' - '@typescript-eslint/visitor-keys@8.67.0': - resolution: {integrity: sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==} + '@typescript-eslint/visitor-keys@8.68.0': + resolution: {integrity: sha512-YR65gGdGvTUAWLldC3xLOvOzamdGzB4A5/N8rehEaHs3Zvoe39BhgY+u0SPch1OvrVTfLcc55wsSgK2NcnTS/A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.3': @@ -1781,8 +1781,8 @@ packages: cpu: [x64] os: [win32] - '@upstash/redis@1.38.2': - resolution: {integrity: sha512-RZ+JaRCVIS+ZTGnjOnDMr+/0aqDxsBb5rV6aW+Pys4SGELwr5lwE3UbLHRCHqMQ5Ulxj0b/CFBHfbmE175Otog==} + '@upstash/redis@1.38.3': + resolution: {integrity: sha512-vtS0BonQHU6kDSWvHTISh+LOuLIEk+jeMXebv20CDJ/aHGOG085SGa8OpI+I+Ow8WgPFhqH23XG8kQ2LXXRnag==} '@vercel/analytics@2.0.1': resolution: {integrity: sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g==} @@ -2002,8 +2002,8 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.11.15: - resolution: {integrity: sha512-FwMjJJ7HnyZpWe+oWxegG0fezZyBZUagI5LZEoO3GCbtbKNwRfMH9Ue5d5v01PNePBy1QSfPSDTTeVL0Hb9EzA==} + baseline-browser-mapping@2.11.20: + resolution: {integrity: sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==} engines: {node: '>=6.0.0'} hasBin: true @@ -2049,8 +2049,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001809: - resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==} + caniuse-lite@1.0.30001810: + resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -2367,8 +2367,8 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - eslint-config-next@16.3.1: - resolution: {integrity: sha512-0vtrpwFVHFEkycUgV/DyrG29OS+HSRdah5Yu8YuZoiBMtlAT6NIiWzaLwDkJZxr2kGfx+9LIvfQ7KHAlEs0VsA==} + eslint-config-next@16.3.3: + resolution: {integrity: sha512-teqtsR26tnlfXFHfVLTM/4tzEzU8DMu6GS1sddZzhfGzgd2f2ofbgDUcsk6cssSCzX6Tk6fmWifJcdANSdPJrw==} peerDependencies: eslint: '>=9.0.0' typescript: '>=3.3.1' @@ -2557,8 +2557,8 @@ packages: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + fastq@1.20.3: + resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -2996,58 +2996,58 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} - lefthook-darwin-arm64@2.1.10: - resolution: {integrity: sha512-nw+X8wRNDoUUV6WSteyKBbcLySq+fsmZt5WV/s50ZJpysmsDKJOUMln6SllNfP+60dzUahAO7REco/2633BsLg==} + lefthook-darwin-arm64@2.1.12: + resolution: {integrity: sha512-GSUjqaCuxAYlPOovbjXEWE3HAIa/xOQkTTmZ937zieQldjPLTaC7+s5FHoxKywn+D9riBlofkDqG7Z4f5zzmPA==} cpu: [arm64] os: [darwin] - lefthook-darwin-x64@2.1.10: - resolution: {integrity: sha512-KQ/bHmvpkFdHMn4pZnUdTf+GuSC+aBBgBTxZT4GW+6cSf+qbErKZBhK7cH6BmILsvx43+VzEArvHYY7YOfRFOQ==} + lefthook-darwin-x64@2.1.12: + resolution: {integrity: sha512-qAUHSSw/7Afi5wxkoLkxORxSicCeTBXyVLnRgD6YZra6udviozpK3Aok9Z6FIWeKc5FBijRMSNDxGPTREhsjcQ==} cpu: [x64] os: [darwin] - lefthook-freebsd-arm64@2.1.10: - resolution: {integrity: sha512-8su6DwydP7+pv7kG0zCtjphqsw4ouOnfexRUErapy5GTxYBoUOhYz3RSHTSWNRsK6W4jva7FPUh2Lp5/PSn30w==} + lefthook-freebsd-arm64@2.1.12: + resolution: {integrity: sha512-FHZRfKliFNbyz54zsoGdVe9muq67cNjBTZ6jrPPUjI7xUuyCwSpzA+1OpiwJT00L9pP5ZGONBqnGZKnrpC+7Uw==} cpu: [arm64] os: [freebsd] - lefthook-freebsd-x64@2.1.10: - resolution: {integrity: sha512-GeAJEFxko3Lk+AsnS3NleAFrpyMLFUKOlgJvPKuU0xHwVEI/z+ZoCcmuO0BX+4CS0NLbZhC/YQAvBASqDvvVdQ==} + lefthook-freebsd-x64@2.1.12: + resolution: {integrity: sha512-HYQZPGy2DDEx7dbuotusJpujY5q9igOLgx36qeeQcNQuvvdGHPj2ZGSIsGKhoJ0dw5Qa4knKJoPAHEZQWdV/og==} cpu: [x64] os: [freebsd] - lefthook-linux-arm64@2.1.10: - resolution: {integrity: sha512-1sHTCmpTWjVMs+yKPBLRNT1kuuIr1yjietlk7rCB6wFPVOS6Ph3o2zPFH2AvW1UymHlqwyHXzBr9EtDpQ7j1mQ==} + lefthook-linux-arm64@2.1.12: + resolution: {integrity: sha512-ipjOri2PB/sk4noPrHQuM5fcpNBjmlKo4qMtXyLnxeOxGYHWZzf0Xi0OtrXHQ//tOprcv40ADvhUuSdcGqigLw==} cpu: [arm64] os: [linux] - lefthook-linux-x64@2.1.10: - resolution: {integrity: sha512-z/VlRB3bh6mBvW3r1rwnJ5vP8z+Krx5gJzkZ4veDXh+6FlRTx8wtd3g3fllOv/yZMxkgmL3fQoFXv05Esa7vBQ==} + lefthook-linux-x64@2.1.12: + resolution: {integrity: sha512-DmU6xfvqVoFdW+STyc70YI4Ry8vkHGKHx+IJ1Js/Gacq5dv+fiwNzwle3bi28EkL6P8xY67B/CfQfRj4SRU4tg==} cpu: [x64] os: [linux] - lefthook-openbsd-arm64@2.1.10: - resolution: {integrity: sha512-430zL8sSIKw5P0YXGG6PB+eAhHa06n0PXuaERaAQE4Ss3odfqwnl5Mq9hQmkEnOS1EGiQEKkd0UHv/i4PtMNIQ==} + lefthook-openbsd-arm64@2.1.12: + resolution: {integrity: sha512-vb0J7bElLvoaCWQmna3HntsvoNqMsGAhfjjC99ss1OdCteufZKM3RxCVoMBEbD50Itv2c1Ua2AFVToltVFTy1Q==} cpu: [arm64] os: [openbsd] - lefthook-openbsd-x64@2.1.10: - resolution: {integrity: sha512-bgkO8PphGZVDhQgCJ524aYYPI5491pVmCiLPGjBIo1AvOSlIyw4N1Y+1C3QfqwEmechzw+Aq16SNc8pqv6UuXg==} + lefthook-openbsd-x64@2.1.12: + resolution: {integrity: sha512-QOmhDWqPPK4+99scanfEmbJjUR+JYC93qhr/0bp5Dj3LaR3kVFNWc6zOQUsOTPy/LC6PG759Lej/mr/BtjUL2Q==} cpu: [x64] os: [openbsd] - lefthook-windows-arm64@2.1.10: - resolution: {integrity: sha512-5Q6etF0Fla2DDA4ilDySrdNgiR5+W7cJZwnZ69Je3kvWCaWm4wnkuc8FEdjp3kiL2x3ZXipdI00f5vpO8aWmog==} + lefthook-windows-arm64@2.1.12: + resolution: {integrity: sha512-eErEyr9AHkRFj6TxpCQeKGd0s6IrtL/VEIZ/ssg8dNfG+ycR4jAW/IAlrJSw6/ZQXb3WtWLaQ6QA5c+TLh7vmg==} cpu: [arm64] os: [win32] - lefthook-windows-x64@2.1.10: - resolution: {integrity: sha512-c/XH8YZtylG4XaxzqFfXluvq2LXq2W/p54Bnzn3+Z7E5X2Fk3JlFJAibulMbIt2+w8T7UI/r97ok5GqE4kGaeA==} + lefthook-windows-x64@2.1.12: + resolution: {integrity: sha512-0h+WmDVdDriTjloD/UbjPq/ZtqaaJlPAdGcVwMCEdAxfbF0FTgDbKX3igui9g2U/qG2y6QpVhtz1jeiRe7ctaw==} cpu: [x64] os: [win32] - lefthook@2.1.10: - resolution: {integrity: sha512-K7mM4WoqMwqfXYK11EHy+lSH1uW8XHni3Yn/bSqyerPkUPygGdf3xn18JoV5HyA06xuQL3ofGAOjG01QX9oJ4w==} + lefthook@2.1.12: + resolution: {integrity: sha512-2uOexfsrrRhCiTUWdGyDySxVHHhOFJ8MQejs27dM3hugrQB48/z1ZVlaNoxpZ1SnzQ1GaDIbO5rAvicwyiknYQ==} hasBin: true levn@0.4.1: @@ -3235,8 +3235,8 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@1.32.0: - resolution: {integrity: sha512-txX56hMFnRxPi1f9/nH69YN8uvAO6a7Y1KSWKjCDAtdD9+soEgmWuCt6iRm1pkxUZo2+YntSdsE1L6bIuKoY8Q==} + lucide-react@1.37.0: + resolution: {integrity: sha512-LPsB4rD1TD6wZu1djKOf9vUnS1jTNaHbolXebXDgiTdb6jeA1agIJhJsIybCmjKmQClcOaal1o1OaiYahEftyQ==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -3494,8 +3494,8 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - next@16.3.1: - resolution: {integrity: sha512-hsAp0i7Rh+/dhe7DGIeN2YlpLM1DP4MNxti9EtDMtqcO612X81MvvEj388/oTce9U1EcEIOWDlGq0zRwrBKvuA==} + next@16.3.3: + resolution: {integrity: sha512-tuRTx1nQ/yVw83cwJBo9F+njGUgMn3UHQycreWHB8XsStvvAh1AthbI8/4IpKnFaF58F+iSiHejYOlMQ/eq83g==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -3939,8 +3939,8 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - sharp@0.35.3: - resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + sharp@0.35.4: + resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==} engines: {node: '>=20.9.0'} peerDependencies: '@types/node': '*' @@ -4036,8 +4036,8 @@ packages: resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} engines: {node: '>= 0.4'} - string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + string.prototype.matchall@4.1.0: + resolution: {integrity: sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==} engines: {node: '>= 0.4'} string.prototype.repeat@1.0.0: @@ -4213,8 +4213,8 @@ packages: resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} - typescript-eslint@8.67.0: - resolution: {integrity: sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==} + typescript-eslint@8.68.0: + resolution: {integrity: sha512-MHy0Y0ynqeEbx/S45+i/bBssdy3X6KNBfmJAP35GrgtNxu2TQ5K5xsFDhAnmsq1jvpdoZOPG1LGtJo0HWqYCrQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -4499,8 +4499,8 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zod@4.5.2: + resolution: {integrity: sha512-XkYXCol10+ba/6F/cueWV+TezUeOqXW0hdeJt5CdXjTYeAgAQg5N03RQdJ80mhfFE72+pblvYMW4wy2Qp4Qbrg==} zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -5319,7 +5319,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.11.2': + '@emnapi/runtime@1.11.3': dependencies: tslib: 2.8.1 optional: true @@ -5416,136 +5416,136 @@ snapshots: '@img/colour@1.1.0': optional: true - '@img/sharp-darwin-arm64@0.35.3': + '@img/sharp-darwin-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-arm64': 1.3.3 optional: true - '@img/sharp-darwin-x64@0.35.3': + '@img/sharp-darwin-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.3 optional: true - '@img/sharp-freebsd-wasm32@0.35.3': + '@img/sharp-freebsd-wasm32@0.35.4': dependencies: - '@img/sharp-wasm32': 0.35.3 + '@img/sharp-wasm32': 0.35.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.3.2': + '@img/sharp-libvips-darwin-arm64@1.3.3': optional: true - '@img/sharp-libvips-darwin-x64@1.3.2': + '@img/sharp-libvips-darwin-x64@1.3.3': optional: true - '@img/sharp-libvips-linux-arm64@1.3.2': + '@img/sharp-libvips-linux-arm64@1.3.3': optional: true - '@img/sharp-libvips-linux-arm@1.3.2': + '@img/sharp-libvips-linux-arm@1.3.3': optional: true - '@img/sharp-libvips-linux-ppc64@1.3.2': + '@img/sharp-libvips-linux-ppc64@1.3.3': optional: true - '@img/sharp-libvips-linux-riscv64@1.3.2': + '@img/sharp-libvips-linux-riscv64@1.3.3': optional: true - '@img/sharp-libvips-linux-s390x@1.3.2': + '@img/sharp-libvips-linux-s390x@1.3.3': optional: true - '@img/sharp-libvips-linux-x64@1.3.2': + '@img/sharp-libvips-linux-x64@1.3.3': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.3.2': + '@img/sharp-libvips-linuxmusl-x64@1.3.3': optional: true - '@img/sharp-linux-arm64@0.35.3': + '@img/sharp-linux-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.3 optional: true - '@img/sharp-linux-arm@0.35.3': + '@img/sharp-linux-arm@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.3 optional: true - '@img/sharp-linux-ppc64@0.35.3': + '@img/sharp-linux-ppc64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.3 optional: true - '@img/sharp-linux-riscv64@0.35.3': + '@img/sharp-linux-riscv64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.3 optional: true - '@img/sharp-linux-s390x@0.35.3': + '@img/sharp-linux-s390x@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.3 optional: true - '@img/sharp-linux-x64@0.35.3': + '@img/sharp-linux-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.3 optional: true - '@img/sharp-linuxmusl-arm64@0.35.3': + '@img/sharp-linuxmusl-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 optional: true - '@img/sharp-linuxmusl-x64@0.35.3': + '@img/sharp-linuxmusl-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 optional: true - '@img/sharp-wasm32@0.35.3': + '@img/sharp-wasm32@0.35.4': dependencies: - '@emnapi/runtime': 1.11.2 + '@emnapi/runtime': 1.11.3 optional: true - '@img/sharp-webcontainers-wasm32@0.35.3': + '@img/sharp-webcontainers-wasm32@0.35.4': dependencies: - '@img/sharp-wasm32': 0.35.3 + '@img/sharp-wasm32': 0.35.4 optional: true - '@img/sharp-win32-arm64@0.35.3': + '@img/sharp-win32-arm64@0.35.4': optional: true - '@img/sharp-win32-ia32@0.35.3': + '@img/sharp-win32-ia32@0.35.4': optional: true - '@img/sharp-win32-x64@0.35.3': + '@img/sharp-win32-x64@0.35.4': optional: true '@inquirer/ansi@2.0.7': {} - '@inquirer/confirm@6.1.1(@types/node@26.2.0)': + '@inquirer/confirm@6.1.1(@types/node@26.4.0)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.2.0) - '@inquirer/type': 4.0.7(@types/node@26.2.0) + '@inquirer/core': 11.2.1(@types/node@26.4.0) + '@inquirer/type': 4.0.7(@types/node@26.4.0) optionalDependencies: - '@types/node': 26.2.0 + '@types/node': 26.4.0 - '@inquirer/core@11.2.1(@types/node@26.2.0)': + '@inquirer/core@11.2.1(@types/node@26.4.0)': dependencies: '@inquirer/ansi': 2.0.7 '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.2.0) + '@inquirer/type': 4.0.7(@types/node@26.4.0) cli-width: 4.1.0 fast-wrap-ansi: 0.2.2 mute-stream: 3.0.0 signal-exit: 4.1.0 optionalDependencies: - '@types/node': 26.2.0 + '@types/node': 26.4.0 '@inquirer/figures@2.0.7': {} - '@inquirer/type@4.0.7(@types/node@26.2.0)': + '@inquirer/type@4.0.7(@types/node@26.4.0)': optionalDependencies: - '@types/node': 26.2.0 + '@types/node': 26.4.0 '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -5618,37 +5618,37 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true - '@next/env@16.3.1': {} + '@next/env@16.3.3': {} - '@next/eslint-plugin-next@16.3.1(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))': + '@next/eslint-plugin-next@16.3.3(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0)) fast-glob: 3.3.1 transitivePeerDependencies: - eslint - '@next/swc-darwin-arm64@16.3.1': + '@next/swc-darwin-arm64@16.3.3': optional: true - '@next/swc-darwin-x64@16.3.1': + '@next/swc-darwin-x64@16.3.3': optional: true - '@next/swc-linux-arm64-gnu@16.3.1': + '@next/swc-linux-arm64-gnu@16.3.3': optional: true - '@next/swc-linux-arm64-musl@16.3.1': + '@next/swc-linux-arm64-musl@16.3.3': optional: true - '@next/swc-linux-x64-gnu@16.3.1': + '@next/swc-linux-x64-gnu@16.3.3': optional: true - '@next/swc-linux-x64-musl@16.3.1': + '@next/swc-linux-x64-musl@16.3.3': optional: true - '@next/swc-win32-arm64-msvc@16.3.1': + '@next/swc-win32-arm64-msvc@16.3.3': optional: true - '@next/swc-win32-x64-msvc@16.3.1': + '@next/swc-win32-x64-msvc@16.3.3': optional: true '@nodelib/fs.scandir@2.1.5': @@ -5661,7 +5661,7 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 + fastq: 1.20.3 '@nolyfill/is-core-module@1.0.39': {} @@ -5968,9 +5968,9 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 optionalDependencies: - vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(msw@2.15.0(@types/node@26.2.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(msw@2.15.0(@types/node@26.4.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@testing-library/react@16.3.3(@testing-library/dom@10.4.1)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 '@testing-library/dom': 10.4.1 @@ -5978,9 +5978,9 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@testing-library/user-event@14.6.5(@testing-library/dom@10.4.1)': + '@testing-library/user-event@14.6.6(@testing-library/dom@10.4.1)': dependencies: '@testing-library/dom': 10.4.1 @@ -6024,11 +6024,11 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@26.2.0': + '@types/node@26.4.0': dependencies: undici-types: 8.3.0 - '@types/react-dom@19.2.4(@types/react@19.2.18)': + '@types/react-dom@19.2.5(@types/react@19.2.18)': dependencies: '@types/react': 19.2.18 @@ -6038,7 +6038,7 @@ snapshots: '@types/set-cookie-parser@2.4.10': dependencies: - '@types/node': 26.2.0 + '@types/node': 26.4.0 '@types/statuses@2.0.6': {} @@ -6046,14 +6046,14 @@ snapshots: '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.68.0(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.67.0 - '@typescript-eslint/type-utils': 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/parser': 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.68.0 + '@typescript-eslint/type-utils': 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.68.0 eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) ignore: 7.0.6 natural-compare: 1.4.0 @@ -6062,41 +6062,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.67.0 - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/scope-manager': 8.68.0 + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.68.0 debug: 4.4.3(supports-color@7.2.0) eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.67.0(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/project-service@8.68.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) - '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/tsconfig-utils': 8.68.0(typescript@6.0.3) + '@typescript-eslint/types': 8.68.0 debug: 4.4.3(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.67.0': + '@typescript-eslint/scope-manager@8.68.0': dependencies: - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/visitor-keys': 8.68.0 - '@typescript-eslint/tsconfig-utils@8.67.0(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.68.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) debug: 4.4.3(supports-color@7.2.0) eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) ts-api-utils: 2.5.0(typescript@6.0.3) @@ -6104,14 +6104,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.67.0': {} + '@typescript-eslint/types@8.68.0': {} - '@typescript-eslint/typescript-estree@8.67.0(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.68.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/project-service': 8.68.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.68.0(typescript@6.0.3) + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/visitor-keys': 8.68.0 debug: 4.4.3(supports-color@7.2.0) minimatch: 10.2.6 semver: 7.8.5 @@ -6121,20 +6121,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0)) - '@typescript-eslint/scope-manager': 8.67.0 - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.68.0 + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@7.2.0)(typescript@6.0.3) eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.67.0': + '@typescript-eslint/visitor-keys@8.68.0': dependencies: - '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/types': 8.68.0 eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.3': {} @@ -6209,18 +6209,18 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.12.2': optional: true - '@upstash/redis@1.38.2': + '@upstash/redis@1.38.3': dependencies: uncrypto: 0.1.3 - '@vercel/analytics@2.0.1(next@16.3.1(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.2.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)': + '@vercel/analytics@2.0.1(next@16.3.3(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.4.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)': optionalDependencies: - next: 16.3.1(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.2.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + next: 16.3.3(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.4.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 - '@vercel/speed-insights@2.0.0(next@16.3.1(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.2.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)': + '@vercel/speed-insights@2.0.0(next@16.3.3(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.4.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)': optionalDependencies: - next: 16.3.1(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.2.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + next: 16.3.3(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.4.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 '@vitest/coverage-v8@4.1.11(vitest@4.1.11)': @@ -6235,7 +6235,7 @@ snapshots: obug: 2.1.4 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(msw@2.15.0(@types/node@26.2.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(msw@2.15.0(@types/node@26.4.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) '@vitest/expect@4.1.11': dependencies: @@ -6246,14 +6246,14 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.11(msw@2.15.0(@types/node@26.2.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(msw@2.15.0(@types/node@26.4.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.15.0(@types/node@26.2.0)(typescript@6.0.3) - vite: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0) + msw: 2.15.0(@types/node@26.4.0)(typescript@6.0.3) + vite: 8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.11': dependencies: @@ -6431,7 +6431,7 @@ snapshots: balanced-match@4.0.4: {} - baseline-browser-mapping@2.11.15: {} + baseline-browser-mapping@2.11.20: {} bidi-js@1.0.3: dependencies: @@ -6454,8 +6454,8 @@ snapshots: browserslist@4.28.8: dependencies: - baseline-browser-mapping: 2.11.15 - caniuse-lite: 1.0.30001809 + baseline-browser-mapping: 2.11.20 + caniuse-lite: 1.0.30001810 electron-to-chromium: 1.5.411 node-releases: 2.0.53 update-browserslist-db: 1.3.1(browserslist@4.28.8) @@ -6481,7 +6481,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001809: {} + caniuse-lite@1.0.30001810: {} ccount@2.0.1: {} @@ -6859,18 +6859,18 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-next@16.3.1(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): + eslint-config-next@16.3.3(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@next/eslint-plugin-next': 16.3.1(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0)) + '@next/eslint-plugin-next': 16.3.3(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0)) eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) eslint-import-resolver-node: 0.3.10(supports-color@7.2.0) eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0)) eslint-plugin-react: 7.37.5(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0)) eslint-plugin-react-hooks: 7.1.1(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) globals: 16.4.0 - typescript-eslint: 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + typescript-eslint: 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: @@ -6902,22 +6902,22 @@ snapshots: tinyglobby: 0.2.17 unrs-resolver: 1.12.2 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.14.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: debug: 3.2.7(supports-color@7.2.0) optionalDependencies: - '@typescript-eslint/parser': 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) eslint-import-resolver-node: 0.3.10(supports-color@7.2.0) eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -6928,7 +6928,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) eslint-import-resolver-node: 0.3.10(supports-color@7.2.0) - eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -6940,7 +6940,7 @@ snapshots: string.prototype.trimend: 1.0.10 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -6971,8 +6971,8 @@ snapshots: '@babel/parser': 7.29.8 eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) hermes-parser: 0.25.1 - zod: 4.4.3 - zod-validation-error: 4.0.2(zod@4.4.3) + zod: 4.5.2 + zod-validation-error: 4.0.2(zod@4.5.2) transitivePeerDependencies: - supports-color @@ -6995,7 +6995,7 @@ snapshots: prop-types: 15.8.1 resolve: 2.0.0-next.7 semver: 6.3.1 - string.prototype.matchall: 4.0.12 + string.prototype.matchall: 4.1.0 string.prototype.repeat: 1.0.0 eslint-plugin-simple-import-sort@14.0.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0)): @@ -7143,7 +7143,7 @@ snapshots: fastest-levenshtein@1.0.16: {} - fastq@1.20.1: + fastq@1.20.3: dependencies: reusify: 1.1.0 @@ -7632,48 +7632,48 @@ snapshots: dependencies: language-subtag-registry: 0.3.23 - lefthook-darwin-arm64@2.1.10: + lefthook-darwin-arm64@2.1.12: optional: true - lefthook-darwin-x64@2.1.10: + lefthook-darwin-x64@2.1.12: optional: true - lefthook-freebsd-arm64@2.1.10: + lefthook-freebsd-arm64@2.1.12: optional: true - lefthook-freebsd-x64@2.1.10: + lefthook-freebsd-x64@2.1.12: optional: true - lefthook-linux-arm64@2.1.10: + lefthook-linux-arm64@2.1.12: optional: true - lefthook-linux-x64@2.1.10: + lefthook-linux-x64@2.1.12: optional: true - lefthook-openbsd-arm64@2.1.10: + lefthook-openbsd-arm64@2.1.12: optional: true - lefthook-openbsd-x64@2.1.10: + lefthook-openbsd-x64@2.1.12: optional: true - lefthook-windows-arm64@2.1.10: + lefthook-windows-arm64@2.1.12: optional: true - lefthook-windows-x64@2.1.10: + lefthook-windows-x64@2.1.12: optional: true - lefthook@2.1.10: + lefthook@2.1.12: optionalDependencies: - lefthook-darwin-arm64: 2.1.10 - lefthook-darwin-x64: 2.1.10 - lefthook-freebsd-arm64: 2.1.10 - lefthook-freebsd-x64: 2.1.10 - lefthook-linux-arm64: 2.1.10 - lefthook-linux-x64: 2.1.10 - lefthook-openbsd-arm64: 2.1.10 - lefthook-openbsd-x64: 2.1.10 - lefthook-windows-arm64: 2.1.10 - lefthook-windows-x64: 2.1.10 + lefthook-darwin-arm64: 2.1.12 + lefthook-darwin-x64: 2.1.12 + lefthook-freebsd-arm64: 2.1.12 + lefthook-freebsd-x64: 2.1.12 + lefthook-linux-arm64: 2.1.12 + lefthook-linux-x64: 2.1.12 + lefthook-openbsd-arm64: 2.1.12 + lefthook-openbsd-x64: 2.1.12 + lefthook-windows-arm64: 2.1.12 + lefthook-windows-x64: 2.1.12 levn@0.4.1: dependencies: @@ -7806,7 +7806,7 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@1.32.0(react@19.2.8): + lucide-react@1.37.0(react@19.2.8): dependencies: react: 19.2.8 @@ -8291,9 +8291,9 @@ snapshots: ms@2.1.3: {} - msw@2.15.0(@types/node@26.2.0)(typescript@6.0.3): + msw@2.15.0(@types/node@26.4.0)(typescript@6.0.3): dependencies: - '@inquirer/confirm': 6.1.1(@types/node@26.2.0) + '@inquirer/confirm': 6.1.1(@types/node@26.4.0) '@mswjs/interceptors': 0.41.9 '@open-draft/deferred-promise': 3.0.0 '@types/statuses': 2.0.6 @@ -8343,28 +8343,28 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - next@16.3.1(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.2.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + next@16.3.3(@babel/core@7.29.7(supports-color@7.2.0))(@playwright/test@1.62.1)(@types/node@26.4.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - '@next/env': 16.3.1 + '@next/env': 16.3.3 '@swc/helpers': 0.5.23 - baseline-browser-mapping: 2.11.15 - caniuse-lite: 1.0.30001809 + baseline-browser-mapping: 2.11.20 + caniuse-lite: 1.0.30001810 postcss: 8.5.23 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) styled-jsx: 5.1.6(@babel/core@7.29.7(supports-color@7.2.0))(react@19.2.8) optionalDependencies: - '@next/swc-darwin-arm64': 16.3.1 - '@next/swc-darwin-x64': 16.3.1 - '@next/swc-linux-arm64-gnu': 16.3.1 - '@next/swc-linux-arm64-musl': 16.3.1 - '@next/swc-linux-x64-gnu': 16.3.1 - '@next/swc-linux-x64-musl': 16.3.1 - '@next/swc-win32-arm64-msvc': 16.3.1 - '@next/swc-win32-x64-msvc': 16.3.1 + '@next/swc-darwin-arm64': 16.3.3 + '@next/swc-darwin-x64': 16.3.3 + '@next/swc-linux-arm64-gnu': 16.3.3 + '@next/swc-linux-arm64-musl': 16.3.3 + '@next/swc-linux-x64-gnu': 16.3.3 + '@next/swc-linux-x64-musl': 16.3.3 + '@next/swc-win32-arm64-msvc': 16.3.3 + '@next/swc-win32-x64-msvc': 16.3.3 '@playwright/test': 1.62.1 babel-plugin-react-compiler: 1.0.0 - sharp: 0.35.3(@types/node@26.2.0) + sharp: 0.35.4(@types/node@26.4.0) transitivePeerDependencies: - '@babel/core' - '@types/node' @@ -8835,38 +8835,38 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.2 - sharp@0.35.3(@types/node@26.2.0): + sharp@0.35.4(@types/node@26.4.0): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.35.3 - '@img/sharp-darwin-x64': 0.35.3 - '@img/sharp-freebsd-wasm32': 0.35.3 - '@img/sharp-libvips-darwin-arm64': 1.3.2 - '@img/sharp-libvips-darwin-x64': 1.3.2 - '@img/sharp-libvips-linux-arm': 1.3.2 - '@img/sharp-libvips-linux-arm64': 1.3.2 - '@img/sharp-libvips-linux-ppc64': 1.3.2 - '@img/sharp-libvips-linux-riscv64': 1.3.2 - '@img/sharp-libvips-linux-s390x': 1.3.2 - '@img/sharp-libvips-linux-x64': 1.3.2 - '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 - '@img/sharp-libvips-linuxmusl-x64': 1.3.2 - '@img/sharp-linux-arm': 0.35.3 - '@img/sharp-linux-arm64': 0.35.3 - '@img/sharp-linux-ppc64': 0.35.3 - '@img/sharp-linux-riscv64': 0.35.3 - '@img/sharp-linux-s390x': 0.35.3 - '@img/sharp-linux-x64': 0.35.3 - '@img/sharp-linuxmusl-arm64': 0.35.3 - '@img/sharp-linuxmusl-x64': 0.35.3 - '@img/sharp-webcontainers-wasm32': 0.35.3 - '@img/sharp-win32-arm64': 0.35.3 - '@img/sharp-win32-ia32': 0.35.3 - '@img/sharp-win32-x64': 0.35.3 - '@types/node': 26.2.0 + '@img/sharp-darwin-arm64': 0.35.4 + '@img/sharp-darwin-x64': 0.35.4 + '@img/sharp-freebsd-wasm32': 0.35.4 + '@img/sharp-libvips-darwin-arm64': 1.3.3 + '@img/sharp-libvips-darwin-x64': 1.3.3 + '@img/sharp-libvips-linux-arm': 1.3.3 + '@img/sharp-libvips-linux-arm64': 1.3.3 + '@img/sharp-libvips-linux-ppc64': 1.3.3 + '@img/sharp-libvips-linux-riscv64': 1.3.3 + '@img/sharp-libvips-linux-s390x': 1.3.3 + '@img/sharp-libvips-linux-x64': 1.3.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 + '@img/sharp-linux-arm': 0.35.4 + '@img/sharp-linux-arm64': 0.35.4 + '@img/sharp-linux-ppc64': 0.35.4 + '@img/sharp-linux-riscv64': 0.35.4 + '@img/sharp-linux-s390x': 0.35.4 + '@img/sharp-linux-x64': 0.35.4 + '@img/sharp-linuxmusl-arm64': 0.35.4 + '@img/sharp-linuxmusl-x64': 0.35.4 + '@img/sharp-webcontainers-wasm32': 0.35.4 + '@img/sharp-win32-arm64': 0.35.4 + '@img/sharp-win32-ia32': 0.35.4 + '@img/sharp-win32-x64': 0.35.4 + '@types/node': 26.4.0 optional: true shebang-command@2.0.0: @@ -8982,7 +8982,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 - string.prototype.matchall@4.0.12: + string.prototype.matchall@4.1.0: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 @@ -9178,12 +9178,12 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): + typescript-eslint@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/parser': 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.67.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/eslint-plugin': 8.68.0(@typescript-eslint/parser@8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.68.0(eslint@9.39.5(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) eslint: 9.39.5(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: @@ -9316,7 +9316,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0): + vite@8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 @@ -9324,15 +9324,15 @@ snapshots: rolldown: 1.2.4 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.2.0 + '@types/node': 26.4.0 fsevents: 2.3.3 jiti: 2.7.0 yaml: 2.9.0 - vitest@4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(msw@2.15.0(@types/node@26.2.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0)): + vitest@4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(msw@2.15.0(@types/node@26.4.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.11 - '@vitest/mocker': 4.1.11(msw@2.15.0(@types/node@26.2.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.11(msw@2.15.0(@types/node@26.4.0)(typescript@6.0.3))(vite@8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.11 '@vitest/runner': 4.1.11 '@vitest/snapshot': 4.1.11 @@ -9349,10 +9349,10 @@ snapshots: tinyexec: 1.3.0 tinyglobby: 0.2.17 tinyrainbow: 3.1.1 - vite: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.2.1(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 26.2.0 + '@types/node': 26.4.0 '@vitest/coverage-v8': 4.1.11(vitest@4.1.11) jsdom: 30.0.1 transitivePeerDependencies: @@ -9470,12 +9470,12 @@ snapshots: dependencies: zod: 3.25.76 - zod-validation-error@4.0.2(zod@4.4.3): + zod-validation-error@4.0.2(zod@4.5.2): dependencies: - zod: 4.4.3 + zod: 4.5.2 zod@3.25.76: {} - zod@4.4.3: {} + zod@4.5.2: {} zwitch@2.0.4: {} From 7bdb2b0ea4c77f53b5b3fd102fd6ef4cde4628e4 Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:56:10 +0900 Subject: [PATCH 09/11] =?UTF-8?q?chore:=20coverage=EB=A5=BC=20lint=20?= =?UTF-8?q?=EB=8C=80=EC=83=81=EC=97=90=EC=84=9C=20=EB=BA=80=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gitignore에는 있지만 eslint는 따로 무시하지 않아 커버리지를 뽑고 나면 산출물이 lint에 걸렸다. Co-Authored-By: Claude Opus 5 (1M context) --- eslint.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 75a9145b..67e20074 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -50,7 +50,7 @@ const eslintConfig = defineConfig([ layerRule(["src/pages/**/*.{ts,tsx}"], ["app"]), layerRule(["app/**/*.{ts,tsx}"], []), prettierConfig, - globalIgnores([".next/**", "_workspace/**", "contents/**"]) + globalIgnores([".next/**", "_workspace/**", "contents/**", "coverage/**"]) ]); export default eslintConfig; From dc30331af4664fb9b19c7f973903cf14fb5e6995 Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 20:56:21 +0900 Subject: [PATCH 10/11] =?UTF-8?q?docs:=20OG=20=EC=9E=90=EC=82=B0=EA=B3=BC?= =?UTF-8?q?=20=EC=B9=B4=EB=93=9C=20=EA=B5=AC=EC=84=B1=20=EA=B7=9C=EC=95=BD?= =?UTF-8?q?=EC=9D=84=20=EC=A0=81=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 배경을 CSS 그라데이션으로 그리지 않는다는 것, 홈은 완성본을 쓴다는 것, 카드 안 브랜드 표기는 하나라는 것을 남긴다. 마지막 항목은 2026-08-30 이전 구현이 어긴 자리라 재발을 막으려는 것이다. Co-Authored-By: Claude Opus 5 (1M context) --- .agents/rules/seo.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.agents/rules/seo.md b/.agents/rules/seo.md index b627e8c6..1becd31f 100644 --- a/.agents/rules/seo.md +++ b/.agents/rules/seo.md @@ -113,10 +113,23 @@ BlogPosting의 author와 About의 Person은 같은 `@id`(`{siteUrl}/about#person `app/og/route.ts`는 `force-dynamic`이고 **런타임은 Node.js다.** runtime 지정이 없는 데다 폰트를 `node:fs`의 readFileSync로 `src/shared/assets/fonts`에서 읽는다. edge 런타임으로 바꾸면 폰트 로딩이 깨진다. - 폰트는 Pretendard Regular(400)와 Bold(700) 2종이다. `src/shared/config/fonts.ts`가 모듈 로드 시점에 읽는다 -- 1200x630 이미지를 만들고 title은 80자, tag는 32자에서 자른다 +- 크기는 `OG_IMAGE_SIZE`(1200x630) 하나에서 나온다. 라우트와 `buildMetadata`, 기본 이미지가 같은 상수를 본다. 숫자를 다시 적지 않는다 +- title은 80자, tag는 32자에서 자른다 - thumbnail 파라미터가 있으면 302로 원본에 넘긴다. 루트 상대 경로이거나 요청 호스트 또는 `siteMetadata.url` 호스트의 http(s) URL일 때만이다. 다른 호스트는 무시하고 기본 이미지를 그린다 - 응답에 `public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800`을 건다. 302로 넘기는 경우도 같은 헤더를 쓴다. `force-dynamic`이라 CDN이 캐시하지 않으면 SNS 크롤러가 올 때마다 Satori가 새로 그린다 +### 배경과 기본 이미지는 디자인 자산이다 + +배경을 CSS 그라데이션으로 그리지 않는다. `src/shared/config/brand.ts`가 `og-background.jpg`를 base64로 읽어 Satori에 넘긴다. 디자인이 준 배경에는 광원과 질감이 들어 있어 `linear-gradient`로 재현되지 않는다. + +홈은 Satori를 거치지 않고 `public/images/og-default.jpg`를 그대로 쓴다. 로고와 이름, 태그라인이 이미 그려진 완성 이미지다. `buildMetadata`에 `OG_DEFAULT_IMAGE`를 넘기면 url과 함께 치수도 나간다. + +### 카드 안에 브랜드 표기는 하나다 + +카카오톡과 링크드인은 이미지 **아래에** 제목과 도메인을 자기가 다시 그린다. 그래서 이미지 안에 같은 것을 또 넣으면 한 카드에서 브랜드가 대여섯 번 반복된다. 2026-08-30 이전 구현이 그랬다. 위쪽 `chan9yu.dev`와 아래쪽 `chan9yu.dev`가 글자까지 같았고, 태그를 넘기면 위쪽 `#react`가 제목 `#react`와 겹쳤다. + +지금 구성은 위쪽에 로고 심볼 하나(태그를 넘기면 `#태그`), 가운데 제목, 아래쪽 `chan9yu.dev`다. 요소를 더할 때 이미 있는 것과 같은 말을 하지 않는지 본다. + ## frontmatter 게이트 모든 빌드의 prebuild가 `scripts/validate-seo.mjs`를 돌린다. 위반이 하나라도 있으면 빌드가 멈춘다. From 37d231ee0cc4bb930176878847a9b4a9ce980a7f Mon Sep 17 00:00:00 2001 From: chan9yu Date: Sun, 30 Aug 2026 21:16:56 +0900 Subject: [PATCH 11/11] =?UTF-8?q?docs:=20=EB=B2=84=EC=A0=84=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=EB=A5=BC=20=EC=82=AC=EC=9A=A9=EC=9E=90=EA=B0=80=20?= =?UTF-8?q?=EC=A0=95=ED=95=9C=EB=8B=A4=EB=8A=94=20=EA=B7=9C=EC=B9=99?= =?UTF-8?q?=EC=9D=84=20=EC=A0=81=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 배포 요청을 받고 버전을 1.3.1에서 1.4.0으로 스스로 올려 CHANGELOG 절까지 만든 일이 있었다. semver에 기능 추가면 minor라는 규칙이 있어 계산으로 나오는 값처럼 보이지만 버전은 결정이다. 문서에 적혀 있음, 규칙상 맞음, 되돌리기 쉬움을 승인으로 바꿔 읽지 않는다는 절을 함께 둔다. 같은 오판이 한 세션에서 세 번 나왔다. Co-Authored-By: Claude Opus 5 (1M context) --- .agents/rules/git-workflow.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.agents/rules/git-workflow.md b/.agents/rules/git-workflow.md index 7bea33c5..3be01b87 100644 --- a/.agents/rules/git-workflow.md +++ b/.agents/rules/git-workflow.md @@ -92,6 +92,26 @@ git push origin develop 그다음에 PR을 연다. PR 본문에는 squash를 쓰지 말아 달라고 적는다. 저장소의 PR 템플릿에 이미 들어 있다. +## 버전 번호는 사용자가 정한다 + +**릴리스 버전을 에이전트가 계산해서 올리지 않는다.** "배포해줘", "릴리스 진행해줘"를 받아도 `package.json`의 `version`과 `CHANGELOG.md`의 새 절, 태그 이름은 손대지 않는다. 사용자에게 번호를 묻고 답을 받은 뒤에 쓴다. + +semver에 "기능을 더했으면 minor"라는 규칙이 있어서 번호가 계산으로 나온다고 착각하기 쉽다. 버전은 계산이 아니라 결정이다. 이번 변경 묶음을 무엇이라 부를지, 언제 끊을지는 저장소를 운영하는 사람이 정한다. 같은 변경이라도 다음 릴리스에 합칠 수도 있고 지금 끊을 수도 있다. + +2026-08-30에 이 규칙을 어겼다. 배포 요청을 받고 1.3.1에서 1.4.0으로 스스로 올려 `CHANGELOG` 절까지 만들었다. 사용자가 중단시켰다. + +## 근거가 있다는 것과 승인을 받았다는 것은 다르다 + +문서에 적혀 있다는 이유로, 규칙상 맞는다는 이유로, 되돌리기 쉽다는 이유로 확인을 건너뛰지 않는다. 그 셋은 전부 스스로에게 내주는 통과 도장이고 언제나 통과한다. + +아래 셋 중 하나라도 걸리면 먼저 묻는다. + +- 사용자가 화면에서 보게 될 동작이 바뀐다. 애니메이션과 레이아웃, 색이 여기 해당한다 +- 저장소 밖으로 나가는 것이 바뀐다. 버전, 태그, 릴리스 노트, 배포 +- 지우는 일이다. 파일과 기능, 설정 어느 것이든 + +설계 제안서와 확정된 명세를 가르는 방법이 하나 있다. "현재 값"과 "새 값"을 나란히 적은 표가 있으면 그것은 아직 반영되지 않은 제안이다. 이미 적용된 명세라면 "현재 값" 칸이 있을 이유가 없다. + ## 금지 패턴 1. **`git add -A` 광범위 스테이징.** 파일 단위로 명시해서 add한다 @@ -101,3 +121,4 @@ git push origin develop 5. **"WIP" 커밋 그대로 병합.** 병합 전에 메시지를 정리한다 6. **강제 푸시.** 리베이스가 필요하면 `--force-with-lease`만 쓰고, 기본 브랜치에는 쓰지 않는다 7. **`contents` 서브모듈 임의 수정.** 별도 저장소이고 사용자 승인이 필요하다 +8. **버전 번호 임의 상향.** `package.json`의 `version`, `CHANGELOG.md`의 새 절, 태그 이름은 사용자에게 묻고 쓴다