diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4157c81d..8d3d909e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,15 +51,13 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - - name: Lint - run: pnpm lint - - - name: Type check - run: pnpm check-types - - - name: Test - run: pnpm test + # lint/check-types/test는 모두 turbo 태스크. 한 번의 turbo 호출로 묶으면 + # 공유 의존성(^build)을 한 번만 빌드하고 세 태스크를 의존성 그래프에 맞춰 + # 병렬 실행 + 캐싱합니다. (태스크별로 따로 호출하면 ^build가 중복됩니다) + - name: Lint / Type check / Test + run: pnpm turbo run lint check-types test + # turbo 태스크가 아닌 검사들 (가볍게 끝나므로 순차 실행) - name: Lint blog posts (frontmatter) run: pnpm --filter @blog/web lint:posts diff --git a/CLAUDE.md b/CLAUDE.md index 340c96fe..12cb5bc7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -291,5 +291,5 @@ The blog (`apps/blog/web/`) is a **statically generated (SSG) Next.js applicatio ## Prerequisites -- Node.js >= 22 (`apps/blog/web`의 `node --test ''` 글롭 패턴이 22.5+ 필요) -- pnpm 10.10.0 (specified in packageManager field) +- Node.js >= 24 (루트 `engines` 및 `.tool-versions` 기준 24.6.0; `apps/blog/web`의 `node --test ''` 글롭 패턴이 22.5+ 필요) +- pnpm 11.6.0 (specified in packageManager field) diff --git "a/apps/blog/posts/typescript/typescript-6-\354\227\205\352\267\270\353\240\210\354\235\264\353\223\234-\354\202\275\354\247\210\352\270\260.md" "b/apps/blog/posts/typescript/typescript-6-\354\227\205\352\267\270\353\240\210\354\235\264\353\223\234-\354\202\275\354\247\210\352\270\260.md" new file mode 100644 index 00000000..7e848885 --- /dev/null +++ "b/apps/blog/posts/typescript/typescript-6-\354\227\205\352\267\270\353\240\210\354\235\264\353\223\234-\354\202\275\354\247\210\352\270\260.md" @@ -0,0 +1,422 @@ +--- +title: 'TypeScript 6 업그레이드: breaking change 3종을 PR diff까지 추적하며 격파한 기록' +date: '2026-06-16' +status: 'draft' +slug: 'typescript-6-migration-troubleshooting' +excerpt: '공부 삼아 모노레포의 TypeScript를 5.8.3에서 6.0.3으로 올렸더니, baseUrl deprecation·types 기본값 변경·rootDir 요구라는 breaking change 3종이 차례로 빌드를 무너뜨렸다. 각각이 "왜" 그렇게 바뀌었는지 공식 릴리스 노트와 이슈를 넘어 실제 microsoft/TypeScript PR diff까지 파고들어 하나씩 격파한 기록. 보너스로, 빌드에서 마주친 진짜 빌런 — 유지보수가 멈춘 tsup을 tsdown으로 갈아치운 이야기까지.' +tags: ['TypeScript', 'tsdown', 'monorepo', 'troubleshooting', 'breaking-change'] +--- + +이 글은 작업 중 남긴 임시(draft) 기록을 다듬는 중입니다. 환경은 2026-06 기준 TypeScript 6.0.3 / pnpm 11.6.0 / tsdown 0.22.2 / tsup 8.5.1이며, 버전에 따라 동작이 달라질 수 있습니다. 인용한 이슈·PR 번호는 모두 microsoft/TypeScript 기준입니다. + +## 0. TL;DR + +> "catalog에 박힌 TypeScript 5.8.3을 6 최신으로 올려줘." — 공부 삼아 한 줄로 시작했지만, TypeScript 6는 메이저 버전답게 곳곳에서 빌드를 무너뜨렸다. + +이 글은 Turborepo + pnpm 워크스페이스 모노레포에서 TypeScript `5.8.3 → 6.0.3` 업그레이드를 하며 만난 breaking change들을, **"왜 그렇게 바뀌었는지"를 릴리스 노트 → 이슈 → 실제 PR diff까지 추적하면서** 하나씩 격파한 기록이다. 단순 해결 로그가 아니라 "그 변경의 근거"를 파는 게 목적이다. + +| # | 증상 | 왜 TS6가 이렇게 바꿨나 (근거) | 해결 | +|:-------|:----------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------| +| #1 | `TS5101: 'baseUrl' is deprecated` | baseUrl의 숨은 2번째 역할(bare specifier look-up root)이 런타임에 안 맞는 import를 통과시킴 → deprecate ([#62509](https://github.com/microsoft/TypeScript/pull/62509)) | 직접 쓴 곳(react 앱)의 `baseUrl` 제거 (paths는 4.1부터 baseUrl 불필요) | +| #2 | "빌드는 되는데 타입이 빠진 것 같은데?" | `types` 기본값이 "모든 `@types` 자동 포함" → `[]`. flattened `node_modules`에서 수백 개가 전이로 끌려와 빌드 20–50% 낭비 ([#63054](https://github.com/microsoft/TypeScript/pull/63054)) | 전역이 필요한 곳은 이미 `types` 명시돼 있었음 | +| #3 | `TS5011: 'rootDir' must be set` | 추론된 `rootDir`는 입력 파일 집합에 따라 흔들려 출력 레이아웃이 비결정적 → tsconfig 디렉터리로 고정 ([#62418](https://github.com/microsoft/TypeScript/pull/62418)) | `"rootDir": "./src"` 한 줄 | +| 🎁 보너스 | 빌드 때 **안 쓴** baseUrl로 또 `TS5101` | tsup이 dts 빌드에 `baseUrl \|\| '.'`를 **주입**하는데, tsup은 이미 유지보수 중단 | **tsup → tsdown 전환** | + +먼저 한 가지 정정부터. 위 표의 `TS5101`은 baseUrl **전용 에러가 아니다.** TypeScript의 **범용 "deprecated option" 진단**이고, 6.0이 baseUrl을 그 경로에 태웠을 뿐이다. 이 디테일이 왜 중요한지는 #1에서 PR diff로 확인한다. + +--- + +## 1. baseUrl은 왜 deprecated 되었나 (TS5101) + +### 마주침: 이미 알던 손님 + +`baseUrl`이 deprecated된다는 건 이미 알고 있었다. 내 코드에서 `baseUrl`을 실제로 쓰는 곳은 React 앱 하나뿐이었고, `paths`의 접두사 용도였다. + +```jsonc +// apps/react/tsconfig.app.json +{ + "compilerOptions": { + "moduleResolution": "bundler", + // "baseUrl": ".", ← 삭제 + "paths": { + "@/*": ["./src/*"], + "@pages/*": ["./src/pages/*"] + // ... + } + } +} +``` + +그냥 지웠다. `paths`는 [TypeScript 4.1부터 `baseUrl` 없이 동작](https://www.typescriptlang.org/tsconfig/baseUrl.html)한다. + +> "As of TypeScript 4.1, `baseUrl` is no longer required to be set when using `paths`." + +여기서 한 가지 흔한 오해를 짚자. "`moduleResolution: bundler`라서 baseUrl이 필요 없어진 것"이 **아니다.** `paths`가 baseUrl을 요구하지 않게 된 건 moduleResolution 종류와 무관하게 4.1부터의 일이다. 그러니 어떤 resolution 모드든 `paths`만 쓴다면 baseUrl은 그냥 지우면 된다. + +### 왜 deprecated 됐나: baseUrl의 "숨은 두 번째 일" + +해결은 쉬웠지만, **왜** 멀쩡히 동작하던 옵션을 6.0이 하드 에러로 막는지가 궁금했다. [릴리스 노트](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-6-0.html)와 도입 이슈 [#62207](https://github.com/microsoft/TypeScript/issues/62207)을 보면 이유가 명확하다. baseUrl은 두 가지 일을 한다. + +> "Today, `baseUrl` performs two functions: +> - it acts as a prefix for all entries in `paths` +> - it acts as a potential resolution point for all bare paths +> +> But almost nobody realizes that last part." — [issue #62207](https://github.com/microsoft/TypeScript/issues/62207) + +문제는 두 번째다. baseUrl이 모든 bare specifier의 암묵적 해석 지점이 되면서, **번들러/런타임에선 절대 동작하지 않을 import를 타입체커만 "괜찮다"고 통과**시킨다. + +> "...it often meant that many import paths that would never have worked at runtime are considered \"just fine\" by TypeScript." — 릴리스 노트 + +즉 첫 번째 일(paths 접두사)은 4.1 이후 `paths`가 직접 대체할 수 있으니, 위험한 두 번째 일을 없애기 위해 baseUrl 자체를 걷어내는 것이다. 7.0에서는 아예 제거된다. + +> "In TypeScript 7.0, we are not reimplementing `baseUrl`. ... In TypeScript 6.0, we will be deprecating this behavior. Using `baseUrl` will lead to an error which can only be resolved by applying one of the above fixes, or using `--ignoreDeprecations`." — [issue #62207](https://github.com/microsoft/TypeScript/issues/62207) + +### 구현 레벨: TS5101은 baseUrl 전용이 아니다 + +여기서 PR [#62509 "Deprecate baseUrl"](https://github.com/microsoft/TypeScript/pull/62509)의 실제 diff를 보면 재미있는 사실이 드러난다. baseUrl을 위한 **새 에러 코드는 만들어지지 않았다.** 기존 범용 deprecation 진단(우리가 보는 `TS5101`)을 재사용하고, 거기에 마이그레이션 안내용 신규 메시지(코드 `5111`)만 체이닝한다. + +먼저 타입 선언에 `@deprecated`를 단다. + +```diff +// src/compiler/types.ts + alwaysStrict?: boolean; ++ /** @deprecated */ + baseUrl?: string; +``` + +그리고 핵심은 `program.ts`의 `checkDeprecations("6.0", "7.0", ...)` 블록이다. 여기에 baseUrl 분기가 추가됐다. + +```diff +// src/compiler/program.ts + checkDeprecations("6.0", "7.0", createDiagnostic, createDeprecatedDiagnostic => { + if (options.moduleResolution === ModuleResolutionKind.Node10) { +- createDeprecatedDiagnostic("moduleResolution", "node10"); ++ createDeprecatedDiagnostic("moduleResolution", "node10", /*useInstead*/ undefined, ++ Diagnostics.Visit_https_aka_ms_ts6_for_migration_information); ++ } ++ if (options.baseUrl !== undefined) { ++ createDeprecatedDiagnostic("baseUrl", /*value*/ undefined, /*useInstead*/ undefined, ++ Diagnostics.Visit_https_aka_ms_ts6_for_migration_information); + } + }); +``` + +`checkDeprecations("6.0", "7.0", ...)` — 6.0에서 deprecate, 7.0에서 제거라는 의미가 함수 인자에 그대로 박혀 있다. 그래서 우리가 보는 에러는 이렇게 생겼다. + +```text +error TS5101: Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0. + Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error. + Visit https://aka.ms/ts6 for migration information. +``` + +`TS5101`은 "Option '{0}' is deprecated..."라는 **범용 메시지**의 코드고, `{0}`에 `baseUrl`이, 안내 링크(`Visit https://aka.ms/ts6 ...`)에 신규 코드 `5111`이 related로 붙은 것이다. 그러니 `ignoreDeprecations: "6.0"`으로 한시적으로 끌 수는 있지만, 그건 그저 문제를 7.0으로 미루는 일이다. + +참고로 에러가 가리키는 https://aka.ms/ts6은 마이그레이션 가이드 이슈(#62508)로 리다이렉트되는데, 이 글을 쓰는 시점엔 본문이 아직 Placeholder만 들어 있는 빈 페이지다. 에러는 친절하게 안내하지만 정작 안내처는 공사 중인 셈. + +--- + +## 2. types 기본값이 []가 된 이유 (그리고 왜 우리 빌드는 멀쩡했나) + +### 의심: 타입이 다 빠졌어야 하는 거 아닌가? + +작업 중간에 의문이 들었다. "TS6에선 `types: []`가 기본이라던데, 그럼 전역 타입이 다 빠졌을 텐데 왜 빌드가 다 되지?" 이건 에러가 아니라 **에러가 안 난 게 더 수상한** 경우였다. + +### 무엇이, 왜 바뀌었나 + +[릴리스 노트](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-6-0.html)와 제안 이슈 [#62195](https://github.com/microsoft/TypeScript/issues/62195)이 명확하다. 기존 `types`의 기본값은 사실상 "`node_modules/@types`를 전부 열거"였다. + +> "for convenience, TypeScript would also include all packages in `node_modules/@types` by default... This can be _very_ expensive, as a normal repository setup these days might transitively pull in hundreds of `@types` packages, especially in multi-project workspaces with flattened `node_modules`." — 릴리스 노트 + +flattened `node_modules`를 쓰는 모노레포에서는 이게 특히 치명적이다. 수백 개의 불필요한 `.d.ts`가 전이적으로 프로그램에 끌려와 파싱/체크 비용을 잡아먹는다. 그래서 기본값을 `[]`로 바꿨고, 효과는 수치로 제시돼 있다. + +> "Many projects we've looked at have improved their build time anywhere from 20-50% just by setting `types` appropriately." — 릴리스 노트 ([원 출처는 #54500](https://github.com/microsoft/TypeScript/issues/54500)) + +### 구현 레벨: "기본값 = []" 대입문은 없다 + +PR [#63054 "Set default `types` array to `[]`; support `\"*\"` wildcard"](https://github.com/microsoft/TypeScript/pull/63054)을 까보면, 흥미롭게도 `options.types = []` 같은 **명시적 기본값 대입은 어디에도 없다.** 자동 열거를 담당하던 `getAutomaticTypeDirectiveNames`의 early-return 조건이 뒤집힌 게 전부다. + +```diff +// src/compiler/moduleNameResolver.ts + export function getAutomaticTypeDirectiveNames(options, host): string[] { +- // Use explicit type list from tsconfig.json +- if (options.types) { +- return options.types; ++ if (!usesWildcardTypes(options)) { ++ return options.types ?? []; + } + // ... 여기 아래(typeRoots 열거)는 이제 "*"가 있을 때만 실행된다 +- return result; ++ return deduplicate(flatten(options.types.map(t => t === "*" ? wildcardMatches : t)), equateValues); + } +``` + +핵심은 `if (options.types)` → `if (!usesWildcardTypes(options))`로 바뀐 한 줄이다. 예전엔 "`types`를 명시 안 하면(undefined) typeRoots를 뒤져 모든 `@types`를 자동 포함"했는데, 이제는 **`types` 배열에 `"*"`가 있을 때만** 열거하고, 그 외에는 `options.types ?? []`를 그대로 돌려준다. `[]` 기본값은 별도 코드가 아니라 이 early-return의 자연스러운 결과다. + +판정 헬퍼도 새로 추가됐다. + +```diff +// src/compiler/utilities.ts ++export function usesWildcardTypes(options: CompilerOptions): options is CompilerOptions & { types: string[] } { ++ return some(options.types, t => t === "*"); ++} +``` + +옛 동작(모든 `@types` 자동 포함)으로 되돌리고 싶으면 `"types": ["*"]`를 쓰면 된다. 위 diff에서 `options.types.map(t => t === "*" ? wildcardMatches : t)` — `"*"`가 있던 **위치에** 열거 결과를 펼쳐 넣어 순서까지 보존한다. + +### 핵심: types가 통제하는 범위는 좁다 + +가장 중요한 포인트. 이 변경은 **`node_modules/@types` 읽기를 중단하는 게 아니다.** import해서 쓰는 타입은 전혀 영향이 없고, 오직 **import 없이 전역(ambient)으로 들어오던 `@types`**만 영향을 받는다. + +> "...this does not mean we will stop reading from `node_modules/@types`, just that the files won't be brought in unless imported, explicitly listed in your `tsconfig.json`'s `types` array... Typically this will only affect users relying on global values and module names, like those brought in from `@types/node` (e.g. the `"fs"` module is globally defined), or a testing framework." — [issue #62195](https://github.com/microsoft/TypeScript/issues/62195) + +```ts +import { foo } from 'some-pkg'; // ← types 설정과 무관하게 타입 붙음 +process.env.NODE_ENV; // ← @types/node 전역. types에 'node' 없으면 에러 +``` + +### 왜 우리 레포는 멀쩡히 빌드됐나 + +답은 싱겁게도 "이미 잘 명시돼 있어서"였다. 전역(ambient)이 필요한 패키지는 전부 `types`를 명시하고 있었다. + +| 패키지 | `types` | TS6 영향 | +|:------------------------|:-----------------------------|:------------------------------| +| next.js | `["node", "vitest/globals"]` | 없음 (명시) | +| socket-server / bundler | `["node"]` | 없음 (명시) | +| react / typescript | `["vitest/globals"]` | 없음 (명시) | +| ui / 공유 base config | 미지정 | 이제 `[]` (그러나 ambient 전역을 안 씀) | + +`types`를 명시 안 한 곳(ui, 공유 base)은 애초에 ambient 전역에 의존하지 않거나, Next.js처럼 `next-env.d.ts`의 `/// `로 충당돼서 통과했다. 즉 "에러가 안 난 것"은 운이 아니라, **TS6가 강제하기 전부터 옳게 적혀 있었던** 덕이다. + +ignoreDeprecationsbaseUrl 같은 deprecated 옵션용이지, types 기본값 변경을 되돌리는 옵션이 아니다. 옛 동작이 필요하면 "types": ["*"]를 쓰면 된다 — 이건 glob이 아니라 "전부 열거"를 뜻하는 special token이다. + +--- + +## 3. rootDir를 명시하라 (TS5011) + +### 마주침: 빌드의 dts emit 단계 + +`@package/sample-lib`의 빌드는 `minibundler && tsc --emitDeclarationOnly` 두 단계다. 앞 단계(번들)는 통과했는데 `tsc`가 깨졌다. + +```text +tsconfig.json:10:5 - error TS5011: The common source directory of 'tsconfig.json' + is './src'. The 'rootDir' setting must be explicitly set to this or another path + to adjust your output's file layout. + Visit https://aka.ms/ts6 for migration information. +``` + +해결은 한 줄. + +```jsonc +// packages/@package/sample-lib/tsconfig.json +{ + "compilerOptions": { + "emitDeclarationOnly": true, + "outDir": "./dist", + "rootDir": "./src", // ← 추가 + "allowJs": true + } +} +``` + +### 왜 추론하던 걸 이제 명시하라고 하나 + +[릴리스 노트](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-6-0.html)와 이슈 [#62194](https://github.com/microsoft/TypeScript/issues/62194)의 논거는 두 가지다. + +> "Previously, if you did not specify a `rootDir`, it was inferred based on the common directory of all non-declaration input files. But this often meant that it was impossible to know if a file belonged to a project without trying to load and parse that project. It also meant that TypeScript had to spend more time inferring that common source directory by analyzing every file path in the program." — 릴리스 노트 + +요점은 **결정성(determinism)**이다. 추론된 rootDir는 입력 파일 집합에 따라 움직인다 — 파일 하나를 추가/제거하면 공통 디렉터리가 이동하고, 그러면 `outDir` 안의 출력 경로 레이아웃이 통째로 달라진다. 게다가 "이 파일이 어느 프로젝트 소속인가"를 알려면 프로젝트를 로드·파싱해봐야만 했다(언어 서비스 성능에도 불리). 그래서 6.0은 기본 rootDir를 **tsconfig.json이 있는 디렉터리로 고정**한다. + +### 구현 레벨: 한 줄짜리 조건 완화 + 신·구 비교 + +PR [#62418 "Assume rootDir is the current configuration directory"](https://github.com/microsoft/TypeScript/pull/62418)은 81개 파일을 건드린 큰 PR이지만, 핵심 로직은 **동일한 한 줄이 세 군데에서 완화된 것**이다. + +```diff +// src/compiler/emitter.ts — getCommonSourceDirectory() +- else if (options.composite && options.configFilePath) { ++ else if (options.configFilePath) { + // Project compilations never infer their root from the input source paths + commonSourceDirectory = getDirectoryPath(normalizeSlashes(options.configFilePath)); +``` + +예전엔 `composite` 프로젝트만 "configDir를 공통 소스 디렉터리로" 썼는데, 이제 `configFilePath`만 있으면(=tsconfig 기반 빌드면) 항상 그렇게 한다. 같은 패턴이 `utilities.ts`, `moduleNameResolver.ts`에도 동일하게 적용됐다. + +그럼 TS5011은 언제 던지나? `program.ts`에 새로 추가된 블록이 **옛 방식과 새 방식의 공통 디렉터리를 비교**해서, 출력 레이아웃이 달라질 때만 에러를 낸다(아래는 핵심만 발췌·정리). + +```diff +// src/compiler/program.ts ++if (!options.noEmit && !options.composite && !options.rootDir && options.configFilePath && ++ (options.outDir || (getEmitDeclarations(options) && options.declarationDir) || options.outFile)) { ++ const dir = getCommonSourceDirectory(); // 새 방식: configDir 기준 ++ const files = mapDefined(/* 실제 emit될 입력 파일들 */); ++ const dir59 = getComputedCommonSourceDirectory(files, /* ... */); // 옛 방식: 입력 파일 기준 ++ if (dir59 !== "" && getCanonicalFileName(dir) !== getCanonicalFileName(dir59)) { ++ // 레이아웃이 바뀐다 → TS5011 ++ createDiagnosticForOption(/* ... */ ++ Diagnostics.The_common_source_directory_of_0_is_1_The_rootDir_setting_must_be_explicitly_set_...); ++ } ++} +``` + +여기서 에러 메시지의 친절함이 설명된다. 메시지의 `'{1}'`(=`'./src'`)은 바로 `dir59` — **옛 방식으로 계산한 공통 디렉터리**다. 우리 sample-lib는 소스가 `./src`에 있어 옛 추론값이 `./src`였는데, 새 기본값은 tsconfig 위치(`.`)라 둘이 어긋난다. 그래서 6.0은 "전엔 `./src`로 잡혔으니, 그 값을 `rootDir`에 명시하라"고 **정답을 알려주며** 멈춘 것이다. `rootDir: "./src"`는 그 안내를 그대로 따른 것뿐이다. + +--- + +## 4. 1차 검증: 여기까지 check-types는 통과 + +세 가지 규칙을 다 맞추고 나니 타입 체크는 깨끗했다. + +- `pnpm check-types` → **5/5 통과** + +자, TypeScript 자체가 바꾼 규칙들은 다 막아냈다. 그런데 전체 빌드(`pnpm build`)를 돌리자, **정작 내가 손대지도 않은 곳**에서 다시 터졌다. 그것도 방금 작별했다고 생각한 그 이름, `baseUrl`로. + +--- + +## 5. 🎁 보너스: 빌드에서 튀어나온 진짜 빌런 — tsup + +### 안 쓴 baseUrl이 왜 또? + +`pnpm build`가 디자인 시스템 패키지의 dts 빌드에 다다른 순간이었다. + +```text +@design-system/ui build: DTS Build start +@design-system/ui build: error TS5101: Option 'baseUrl' is deprecated and will + stop functioning in TypeScript 7.0. Specify compilerOption '"ignoreDeprecations": + "6.0"' to silence this error. +@design-system/ui build: DTS Build error +``` + +또 `TS5101`. 그런데 `@design-system/ui/tsconfig.json`에는 `baseUrl`이 **없다.** #1에서 정리했듯 TS5101은 범용 deprecation 진단이니, 누군가가 내 빌드에 baseUrl을 **주입**하고 있다는 뜻이다. + +### 진단: 범인은 tsup + +범인은 dts 번들러로 쓰던 **tsup**이었다. tsup의 소스 [`src/rollup.ts`](https://github.com/egoist/tsup/blob/main/src/rollup.ts)를 직접 까보면: + +```ts +// tsup/src/rollup.ts — dts 빌드 컴파일러 옵션 구성부 +compilerOptions: { + ...compilerOptions, + baseUrl: compilerOptions.baseUrl || '.', // ← 내 tsconfig에 없어도 '.'를 강제 주입 + declaration: true, + // ... +} +``` + +즉 내 tsconfig에 `baseUrl`이 없어도 tsup이 `'.'`로 채워 넣는다. TS 5.x에선 무해했지만, TS6에선 이 주입된 한 줄이 곧장 `TS5101` 하드 에러가 된다. 똑같은 증상이 tsup 이슈 트래커에도 올라와 있다([#1388 "DTS Build error TS5101"](https://github.com/egoist/tsup/issues/1388), 재현 환경 tsup 8.5.1 + TypeScript 6.0.2). + +### 그런데 tsup이… 유지보수 중단? + +"최신 tsup으로 올리면 고쳐졌으려나" 하고 저장소에 갔다가, README 최상단에서 답을 봤다. + +> "This project is not actively maintained anymore. Please consider using tsdown instead." — [egoist/tsup README](https://github.com/egoist/tsup/blob/main/README.md) + +저자(egoist) 본인이 박아둔 문구였다. 실제로 "TypeScript 6 지원" 요청 이슈([#1389](https://github.com/egoist/tsup/issues/1389))는 여전히 열려 있고, 마지막 릴리스 `8.5.1`은 2025-11-12로 한참 전이다. 흥미로운 건 **npm에는 아직 `deprecate` 플래그가 안 걸려 있어서**(그걸 요청하는 이슈가 [#1391](https://github.com/egoist/tsup/issues/1391)) — `pnpm install` 단계에선 아무 경고도 못 보고, 빌드가 깨지고 나서야 README를 보고 알게 됐다는 점이다. + +선택지는 둘이었다. (a) `ignoreDeprecations: "6.0"`으로 경고를 한시적으로 끄거나, (b) 권고대로 도구를 갈아치우거나. baseUrl 주입은 내 코드가 아니라 도구의 문제고, 그 도구가 더는 고쳐지지 않는다면 답은 정해져 있었다. + +### tsdown으로 + +[tsdown](https://tsdown.dev)은 [Rolldown](https://rolldown.rs)(Rust 기반 번들러) 위에서 도는 tsup의 후속 격 도구다. 공식 문서가 관계를 이렇게 정리한다. + +> "tsdown is the spiritual successor to tsup, powered by Rolldown instead of esbuild." — [tsdown FAQ](https://tsdown.dev/guide/faq) + +결정적으로, dts를 [`rolldown-plugin-dts`](https://github.com/sxzz/rolldown-plugin-dts)로 생성하기 때문에 **tsup처럼 baseUrl을 주입하지 않는다.** 그리고 peer dependency로 `typescript: "^5.0.0 || ^6.0.0"`을 선언해 **TS6를 공식 지원**한다(tsup은 아직 open 이슈). tsup을 쓰던 패키지는 둘(`@design-system/ui`, `@package/bundler`)뿐이라 둘 다 전환했다. 공식 마이그레이션 도구도 있다. + +```bash +npx tsdown-migrate # 단일 디렉터리 +npx tsdown-migrate packages/* # 모노레포 glob +npx tsdown-migrate --dry-run # 변경 미리보기 (-d) +``` + +config는 `import`만 바꾸면 거의 그대로다. + +```ts +// packages/@package/bundler/tsdown.config.ts +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['src/index.ts', 'src/cli.ts'], + format: ['esm', 'cjs'], + platform: 'node', + target: 'node24', // ← platform과 다른 축 (함정 ② 참고) + clean: true, + dts: true, + sourcemap: true, +}); +``` + +전환 직후, `TS5101`은 **사라졌다.** 근본 원인(baseUrl 주입)이 없어졌기 때문이다. + +### 함정 ①: 출력 확장자가 다르다 + +다만 공짜는 아니었다. tsdown은 `platform: 'node'`에서 기본적으로 **`.mjs` / `.cjs` / `.d.mts` / `.d.cts`** 확장자로 출력한다(`fixedExtension`). tsup의 `.js` / `.d.ts`와 달라서, `package.json`의 `exports`·`bin`·`main`·`types`가 존재하지 않는 파일을 가리키게 됐다. 실제 산출물에 맞춰 전부 정정해야 했다. + +```jsonc +// @package/bundler/package.json — 실제 산출물에 맞게 수정 +{ + "exports": { + ".": { + "import": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, + "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" } + } + }, + "bin": { "minibundler": "./dist/cli.mjs" } // ← cli.js 가 아니라 cli.mjs +} +``` + +`@design-system/ui`도 마찬가지로 `main`/`types`를 `./dist/index.mjs`·`./dist/index.d.mts`로 맞췄다(이 정정은 별도 커밋으로 떨어졌다 — 산출물 확장자가 바뀌면 이런 메타데이터가 줄줄이 따라온다는 걸 잊지 말 것). + +### 함정 ②: `platform: 'node'`은 `target`이 아니다 + +tsup의 `target: 'node24'`를 옮기며 무심코 `platform: 'node'`로 바꿔 적었는데, 둘은 **다른 축**이다. `platform`은 "이 번들은 Node에서 돈다"는 힌트로 의존성 외부화·조건 해석·기본 출력 확장자(`fixedExtension`) 등에 영향을 주고, **ES 문법 트랜스파일 타겟**은 `target`이 따로 통제한다. `target`을 생략하면 tsdown 기본값이 쓰이므로, Node 24 문법까지 의도대로 내리려면 `target: 'node24'`를 **함께** 명시해야 한다. + +### 함정 ③: 빌드 도구는 `devDependencies`에 + +tsup 시절 `tsup`이 `dependencies`에 들어가 있었고, tsdown으로 바꾸며 그 자리를 그대로 물려줬다. 하지만 빌드 도구(`tsdown`)와 `typescript`는 런타임 의존성이 아니라 **`devDependencies`**에 있어야 한다 — 안 그러면 패키지를 퍼블리시할 때 불필요한 의존성이 딸려간다. `@package/bundler`는 처음부터 devDependencies였는데 `@design-system/ui`만 `dependencies`에 남아 있어 뒤늦게 맞춰 옮겼다. + +```jsonc +// @design-system/ui/package.json +{ + "dependencies": { + "@design-system/ui-lib": "workspace:^" // 런타임 의존성만 + }, + "devDependencies": { + "tsdown": "0.22.2", // ← 빌드 도구 + "typescript": "catalog:" // ← 빌드 타임 + // ... + } +} +``` + +- `pnpm build` (전체) → **9/9 통과** (blog 정적 빌드 포함) + +--- + +## 6. 정리: TypeScript 6 마이그레이션 체크리스트 + +이번 삽질을 한 줄짜리 체크리스트로 압축하면: + +1. **`baseUrl`을 쓰는가?** → 직접 쓰면 제거(`paths`는 4.1부터 baseUrl 불필요). 빌드 도구가 주입한다면 도구를 점검하라. `TS5101`은 baseUrl 전용이 아니라 **범용 deprecated-option 진단**임을 기억할 것. +2. **`@types/node` 같은 전역에 의존하는가?** → `types: ["node", ...]`로 명시. TS6 기본은 `[]`이고, 이는 **ambient 전역에만** 영향을 준다(import 타입은 무관). 옛 동작은 `["*"]`. +3. **`emitDeclarationOnly`/`outDir`로 emit하는데 소스가 tsconfig보다 깊은가?** → `rootDir`을 명시. 에러 메시지의 `'{1}'`이 곧 넣어야 할 값이다. +4. **dts 번들러가 tsup인가?** → tsup은 유지보수가 멈췄고 dts에 baseUrl을 주입한다. tsdown으로 전환하고(`npx tsdown-migrate`), ⓐ 출력 확장자(`.mjs`/`.d.mts`)에 맞춰 `exports`/`bin`/`main`/`types`를 고치고, ⓑ `platform`과 `target`은 다른 축이니 ES 타겟이 필요하면 `target`을 따로 명시하고, ⓒ 빌드 도구(`tsdown`)·`typescript`는 `devDependencies`에 두라. +5. **버전을 일괄 갱신했는가?** → 하위 패키지에 박힌 `packageManager`·`engines` 필드가 루트와 어긋나 있지 않은지 확인하라. (루트는 `pnpm@11.6.0`인데 한 패키지에 `pnpm@10.4.1`이 남아 있었다.) + +곁가지 — 작업 중 node_modules와 빌드 산출물을 수없이 지웠던 터라, 외부 의존성 없이 macOS find로 도는 clean 스크립트를 루트에 넣어뒀다. 핵심은 -name node_modules -prune으로 node_modules 내부를 가지치기하는 것 — 안 그러면 의존성 안의 수많은 dist까지 매칭돼 느리고 위험하다. + +```jsonc +"clean:dist": "find . -name node_modules -prune -o -type d '(' -name dist -o -name .next -o -name out -o -name .turbo ')' -prune -exec rm -rf {} +", +"clean:modules": "find . -name node_modules -type d -prune -exec rm -rf {} +" +``` + +> 메이저 업그레이드는 버전 숫자 하나 바꾸는 일처럼 보여도, 그 숫자가 건드리는 **기본값과 빌드 파이프라인의 가정들**을 전부 다시 확인하게 만든다. 이번엔 그 가정이 `baseUrl`, `types`, `rootDir` 세 군데에 숨어 있었고, 마지막 하나는 TypeScript가 아니라 **유지보수가 멈춘 내 빌드 도구** 안에 있었다. + +--- + +## 참고 링크 + +- TypeScript 6.0 릴리스 노트 — +- baseUrl deprecation: [issue #62207](https://github.com/microsoft/TypeScript/issues/62207) · [PR #62509](https://github.com/microsoft/TypeScript/pull/62509) +- types 기본값 `[]`: [issue #62195](https://github.com/microsoft/TypeScript/issues/62195) · [PR #63054](https://github.com/microsoft/TypeScript/pull/63054) · [원 rationale #54500](https://github.com/microsoft/TypeScript/issues/54500) +- rootDir 기본값: [issue #62194](https://github.com/microsoft/TypeScript/issues/62194) · [PR #62418](https://github.com/microsoft/TypeScript/pull/62418) +- tsup: [README](https://github.com/egoist/tsup/blob/main/README.md) · [TS5101 이슈 #1388](https://github.com/egoist/tsup/issues/1388) · [TS6 지원 #1389](https://github.com/egoist/tsup/issues/1389) +- tsdown: [공식 문서](https://tsdown.dev) · [tsup → tsdown 마이그레이션](https://tsdown.dev/guide/migrate-from-tsup) · [rolldown-plugin-dts](https://github.com/sxzz/rolldown-plugin-dts) diff --git a/apps/blog/web/.gitignore b/apps/blog/web/.gitignore index 83e312cb..9fb704b9 100644 --- a/apps/blog/web/.gitignore +++ b/apps/blog/web/.gitignore @@ -17,6 +17,12 @@ /.next/ /out/ +# generated blog content artifacts (scripts/build-content.ts — regenerated on prebuild/predev) +/public/rss.xml +/public/sitemap.xml +/public/search-index.json +/public/llms-full.txt + # production /build diff --git a/apps/blog/web/package.json b/apps/blog/web/package.json index aaf5599c..fac1a66d 100644 --- a/apps/blog/web/package.json +++ b/apps/blog/web/package.json @@ -41,8 +41,8 @@ "next": "catalog:", "nuqs": "^2.8.8", "pretendard": "^1.3.9", - "react": "catalog:react19", - "react-dom": "catalog:react19", + "react": "catalog:", + "react-dom": "catalog:", "react-markdown": "^10.1.0", "react-medium-image-zoom": "^5.4.5", "react-syntax-highlighter": "^16.1.0", @@ -62,8 +62,8 @@ "@types/mdx": "^2.0.13", "@types/mime-types": "^3.0.1", "@types/node": "^25.8.0", - "@types/react": "catalog:react19", - "@types/react-dom": "catalog:react19", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", "@types/react-syntax-highlighter": "^15.5.13", "@vitejs/plugin-react": "^5.0.4", "babel-plugin-react-compiler": "^1.0.0", @@ -76,7 +76,7 @@ "satori": "^0.26.0", "supabase": "^2.70.5", "tsx": "^4.22.0", - "typescript": "catalog:typescript5", + "typescript": "catalog:", "vitest": "^4.0.0-beta.15" } } diff --git a/apps/blog/web/public/llms-full.txt b/apps/blog/web/public/llms-full.txt deleted file mode 100644 index 0df5d825..00000000 --- a/apps/blog/web/public/llms-full.txt +++ /dev/null @@ -1,217 +0,0 @@ -# Frontend Lab - -> Frontend engineering blog by Sangwook Han (한상욱). Deep-dive technical experiments in bundler architecture, TypeScript domain modeling, React patterns, and open source contributions. All posts include working code and first-hand implementation experience. Content primarily in Korean. - -## Key Facts - -- Author: Sangwook Han (한상욱), Frontend Engineer -- Blog: https://blog.sangwook.dev -- GitHub: https://github.com/Han5991 -- LinkedIn: https://www.linkedin.com/in/sangwook-han/ -- Language: Primarily Korean, some English -- Total posts: 41+ articles -- Open source: 27 Mantine PRs merged, Node.js core contributor, Next.js contributor -- Notable contribution: gemini-cli 74% performance improvement (408ms → 107ms) -- Speaking: FEConf 2025 (Korea's largest frontend conference), TeoConf -- Main topics: Bundler internals, TypeScript domain modeling, React patterns, design systems, open source - ---- - -## 시리즈: [Typescript로 설계하는 프로젝트] - -### [[Typescript로 설계하는 프로젝트] 당신의 Type, 어디까지 연결되어 있나요?](https://blog.sangwook.dev/posts/typescript-project-design/) (2025-05-05) - -[타입으로 설계하는 프로젝트] 당신의 Type, 어디까지 연결되어 있나요? 들어가며 플래닝이 끝나고 난 뒤 저에게 주어진 테스크를 살펴 봅니다. "뭐시기 뭐시기 기능 수정 및 삭제" 큰 기능 아니니 그냥 지워도 될거라는 저의 생각은 조만간 큰 버그를 가져왔습니다. 테스트 서버에 올려보니...... - -### [[Typescript로 설계하는 프로젝트] Type 설계의 시작: 견고한 서버 API Type 설계하기](https://blog.sangwook.dev/posts/typescript-project-api-design/) (2025-06-01) - -들어가며 피곤에 쩔은 모습으로 하나의 테스크를 마무리 하는 순간 백엔드 개발자가 다가옵니다. "죄송하지만 이번에 만든 api 중에 하나의 리스폰스가 변동 될 것 같습니다." "User로 정의한 스키마 중에 name이 빠질 것 같아요." 순간 머릿속에서 여기저기 대강 흩어져 있는 User...... - -### [[Typescript로 설계하는 프로젝트] Type 설계의 시작: 견고한 서버 API Type 설계하기 With DI](https://blog.sangwook.dev/posts/typescript-project-api-di-design/) (2025-06-01) - -들어가며 피곤에 쩔은 모습으로 하나의 테스크를 마무리 하는 순간 백엔드 개발자가 다가옵니다. "죄송하지만 이번에 만든 api 중에 하나의 리스폰스가 변동 될 것 같습니다." "User로 정의한 스키마 중에 name이 빠질 것 같아요." 순간 머릿속에서 여기저기 대강 흩어져 있는 User...... - -### [[Typescript로 설계하는 프로젝트] "원래 있던 기능이니 금방 하시죠?" 당하지 않는 Service Layer 설계 전략](https://blog.sangwook.dev/posts/typescript-project-service-design/) (2025-06-08) - -들어가며 겨우 백엔드의 요청을 쳐내고 다시 피곤함에전 모습으로 테스크를 마무리하려는 순간 이번엔 제 슬랙이 울립니다. [기획자]: "급하게 기획이 바뀌어서요. 이거 프론트에서 추가로 수정해 주셔야 할 것 같아요. 아직 마무리 다 안 하신 거 맞죠?" [나]: "네 아직 마무리 안 했어요...... - -### [[Typescript로 설계하는 프로젝트] "원래 있던 기능이니 금방 하시죠?" 당하지 않는 Service Layer 설계 전략 With Di](https://blog.sangwook.dev/posts/typescript-project-service-di-design/) (2025-06-08) - -들어가며 겨우 백엔드의 요청을 쳐내고 다시 피곤함에전 모습으로 테스크를 마무리하려는 순간 이번엔 제 슬랙이 울립니다. [기획자]: "급하게 기획이 바뀌어서요. 이거 프론트에서 추가로 수정해 주셔야 할 것 같아요. 아직 마무리 다 안 하신 거 맞죠?" [나]: "네 아직 마무리 안 했어요...... - -### [[Typescript로 설계하는 프로젝트] "같은 로직 또 복사했어요?" Domain 모델로 책임 분리하기](https://blog.sangwook.dev/posts/typescript-project-domain-design/) (2025-06-15) - -들어가며 오후 4시, 또 다시 울리는 슬랙 알림... [기획자]: "저번에 만든 사용자 상태 로직 잘 쓰고 있어요! 그런데 이번엔 사용자가 특정 액션을 할 수 있는지 검증하는 로직도 추가해 주세요." [나]: "네, 어떤 검증 로직인가요?" [기획자]: "사용자가 글을 작성할 수 있는지...... - -### [[Typescript로 설계하는 프로젝트] 타입 한 줄로 552개 파일을 2주 만에 안전하게 수정한 방법](https://blog.sangwook.dev/posts/typescript-project-type-safe-refactor-with-typescript/) (2025-11-06) - -"회원 구조가 바뀌었습니다. 552개 파일을 수정해야 합니다." 보통은 이렇게 됩니다 - 어디를 수정해야 하는지 찾느라 1주 - 수정하다가 놓친 곳 때문에 버그 발생 - 회귀 테스트에 또 1주 - QA에서 엣지 케이스 발견 - 결국 한 달... 하지만 우리는 2주 만에, 사이드 이펙트 ...... - -### [[Typescript로 설계하는 프로젝트] id?: string을 버려라. 상태가 다르면 타입도 달라야 한다.](https://blog.sangwook.dev/posts/typescript-domain-modeling-without-optional/) (2026-03-16) - -1. 프롤로그: 우리가 숨 쉬듯 작성하는 "거짓말" 팀원: "OO님, Post 타입에서 id가 없다고 에디터에서 빨간 줄이 뜨는데, 새 글 작성할 땐 서버 id가 없으니까 그냥 ? 붙여도 될까요?" 프론트엔드 개발을 하다 보면 슬랙이나 코드 리뷰에서 심심치 않게 보게 되는 질문입니다. ...... Tags: TypeScript, Architecture, Data Modeling. - -## 시리즈: bundler - -### [[누가 시키지도 않았는데 번들러 만들기] 0. 프롤로그: 질문이 구현이 되는 순간](https://blog.sangwook.dev/posts/no-one-asked-library-bundler-00-prologue/) (2026-02-02) - -수많은 소스 코드가 어떻게 하나의 결과물로 합쳐질까요? 당연하게 사용하던 번들러의 블랙박스를 열고, 직접 손으로 구현하며 그 답을 찾아봅니다.... Tags: bundler, library, build, tooling, javascript, architecture. - -### [[누가 시키지도 않았는데 번들러 만들기] 1. 개념과 도구: 번들러의 등장 배경](https://blog.sangwook.dev/posts/no-one-asked-library-bundler-01-concept/) (2026-02-02) - -코드를 번들링해야 하는 기술적 이유와 자바스크립트 모듈 시스템의 발전 과정을 살펴봅니다. 또한 번들러 구현의 기반이 되는 Magic String 라이브러리를 소개합니다.... Tags: bundler, javascript, history, esm, magic-string. - -### [[누가 시키지도 않았는데 번들러 만들기] 2. 코드를 데이터로 보는 법 (AST Graph)](https://blog.sangwook.dev/posts/no-one-asked-library-bundler-02-ast-graph/) (2026-02-17) - -정규표현식으로 import 문을 찾으려다 실패한 경험, 그리고 AST 추상 구문 트리를 통해 코드를 데이터로 바라보는 관점을 소개합니다. 파일 시스템을 그래프로 변환하는 과정을 직접 구현해봅니다.... Tags: bundler, javascript, ast, graph, dfs, algorithm. - -### [[누가 시키지도 않았는데 번들러 만들기] 3. 번들링과 스코프: 파일 합치기의 기술](https://blog.sangwook.dev/posts/no-one-asked-library-bundler-03-bundling-scope/) (2026-02-23) - -단순히 파일을 합치는 것과 번들링은 다릅니다. 변수 충돌을 막기 위한 함수 스코프 전략과 브라우저를 위한 런타임 구현 과정을 깊이 있게 다룹니다.... Tags: bundler, javascript, iife, scope, cjs, ast. - -### [[누가 시키지도 않았는데 번들러 만들기] 4. 소스맵: 번들된 코드에서 원본의 흔적 찾기](https://blog.sangwook.dev/posts/no-one-asked-library-bundler-04-sourcemap/) (2026-03-03) - -수천 줄로 합쳐진 번들 파일에서 에러가 나면 어떻게 원본 위치를 찾을까요? 소스맵의 VLQ 인코딩 원리와 magic-string이 변환 이력을 관리하는 방식을 직접 구현하며 이해합니다.... Tags: bundler, javascript, sourcemap, vlq, magic-string, security. - -## 시리즈: 아키텍처 - -### [서버 의존성을 줄여보자 (Feat : 클린 아키텍처)](https://blog.sangwook.dev/posts/reduce-server-dependency-clean-architecture/) (2025-01-13) - -텍스트 기존 클린 아키텍처에서 많이 벗어난 내용이 많습니다. 감안하고 봐주시면 감사하겠습니다. 프롤로그 백엔드 개발자로 시작했지만, 프론트엔드에서 아키텍처 고민을 시작하게 된 이유 저는 자바/스프링으로 커리어를 시작 했습니다. 처음 만든 포트폴리오도 스프링mvc를 사용한 웹사이트 였습니...... - -### [FSD 간단하게 시작해보기](https://blog.sangwook.dev/posts/simple-fsd-start/) (2025-01-21) - -공식홈피를 기반 했지만 제 입맛에 따라 해석 했음을 알려드립니다. 프롤로그 때는 바야흐로 2024년 5월 fsd 아키텍처가 유행하기 시작 했다. 마침 회사의 프로젝트 두개를 하나로 합치는 프로젝트를 시작 하는 나로써는 매우나도 유혹적인 글이었습니다. 하지만 지금 처럼 분석글이 많은 때도...... - -### [결제 시스템 리팩토링: if문 지옥에서 디자인 패턴(Factory, Adapter)으로 탈출하기](https://blog.sangwook.dev/posts/payment-system-architecture/) (2026-01-24) - -"만약 내일 당장 '프랑스'가 서비스 국가로 추가된다면? 그리고 한국에서 '사업자 유형'에 따라 결제 수단이 달라져야 한다면?" 이 질문들이 우리 팀의 결제 시스템 설계를 완전히 바꿔놓았습니다. --- 🎭 Prologue: "팀장님의 무리한(?) 요구" 어느 날 오후, 코드 리뷰 중에...... Tags: TypeScript, Design Pattern, Refactoring, Architecture, Zod, Clean Code. - -## 시리즈: 회고/2025 - -### [개발자에서 기여자로: 기술 블로그와 오픈소스가 바꾼 나의 2025년 상반기](https://blog.sangwook.dev/posts/2025-mid-year-review/) (2025-06-17) - -들어가며 2025년 상반기를 돌아보니, 가장 크게 변화한 것은 "나만 알고 있던 지식을 세상과 나누기 시작 했다"는 점이다. 그동안 개발자로서 쌓아온 경험들과 고민을 글로 정리하고, 오픈소스에 기여 하면서 진정한 의미의 성장을 경험한 상반기였다. --- 🌟 기술 블로그: 지식 공유의 ...... - -### [2025 Teoconf 발표 후기](https://blog.sangwook.dev/posts/2025-teoconf-presentation/) (2025-12-11) - -🎤 발표 후기: ‘내가 하고 싶은 말’ 대신 ‘청중이 가져갈 한 문장’을 찾기까지 이번 테오콘 발표는 내게 하나의 도전이었다. 디자인 시스템 배포라는, 나에게 깊은 경험이지만 청중에게는 다소 생소할 수 있는 주제를 어떻게 풀어낼 것인가. 그리고 그 과정에서 “발표는 기술을 나열하는 자...... - -### [2025 회고: 글 33개, PR 38회, 발표 3회로 '보여주는 개발자'가 되다](https://blog.sangwook.dev/posts/2025-retrospect/) (2025-12-21) - -2025 회고: 글 33개, PR 38회, 발표 3회로 '보여주는 개발자'가 되다 2025년은 "숨어서 잘하는 개발자" 에서 "보여주고 나누는 개발자" 로 방향을 튼 해였습니다. 시작점은 2024년 12월 23일, 한 개발자의 피드백이었습니다. "평소 기술 관련 답변을 잘 해주시는데, ...... - -## 시리즈: design-system-lib-deploy - -### [하루 만에 끝날 줄 알았던 디자인 시스템 배포가 3주 걸린 이유](https://blog.sangwook.dev/posts/npm-deploy-series-0-prologue/) (2025-11-30) - -하루 만에 끝날 줄 알았던 NPM 배포가 3주 걸린 이유 프롤로그: "별거 아니겠지"의 착각 타팀 기획자님이 내 자리로 다가왔다. "개발자님, 저희 팀에서도 그 디자인 시스템 쓸 수 있을까요? 버튼이랑 인풋 컴포넌트가 정말 예쁘던데..." 당시 디자인 시스템은 완성해둔 참이었다. 모노레...... Tags: NPM, 디자인 시스템, 배포, Panda CSS, tsup, 빌드. - -## 시리즈: 우아하게 에러 핸들링 하기 - -### [javascript로 우아하게 Error 핸들링하기](https://blog.sangwook.dev/posts/javascript-error/) (2025-02-27) - -프롤로그 이번 글은 JavaScript에서 동기 및 비동기 상황 모두에 대해 에러를 어떻게 처리할 수 있는지에 대해 다룹니다. 에러 처리는 코드의 안정성과 유지보수성에 큰 영향을 미치므로, 명확하고 일관된 패턴을 적용하는 것이 중요합니다. 이 글에서는 기본적인 try-catch 패턴부터...... - -### [React로 우아하게 Error 핸들링 하기](https://blog.sangwook.dev/posts/react-error/) (2025-03-02) - -0. 프롤로그 React 애플리케이션에서 예기치 않은 에러는 사용자 경험에 치명적인 영향을 미칠 수 있습니다. 이 글에서는 ErrorBoundary와 같은 에러 관리 기법을 바탕으로, 비동기 코드에서 발생하는 에러를 어떻게 처리하고, 의도적인 에러와 의도하지 않은 에러를 구분하여 다루는...... - -### [Next.js로 우아하게 Error 핸들링하기](https://blog.sangwook.dev/posts/nextjs-error/) (2025-03-03) - -0. 프롤로그 이전까지는 javascript의 try catch과 React의 ErrorBoundary로 error 객체의 전파와 핸들링하는 방법에 대해 알아 보았습니다.
- - - Frontend Lab | 프론트엔드 기술 실험과 깊이 있는 학습 내용을 공유하는 공간입니다. - https://blog.sangwook.dev - 프론트엔드 기술 실험과 깊이 있는 학습 내용을 공유하는 공간입니다. - ko - Fri, 12 Jun 2026 11:02:11 GMT - - - [Typescript로 설계하는 프로젝트] id?: string을 버려라. 상태가 다르면 타입도 달라야 한다. - https://blog.sangwook.dev/posts/typescript-domain-modeling-without-optional/ - https://blog.sangwook.dev/posts/typescript-domain-modeling-without-optional/ - Sun, 15 Mar 2026 15:00:00 GMT - 1. 프롤로그: 우리가 숨 쉬듯 작성하는 "거짓말" 팀원: "OO님, Post 타입에서 id가 없다고 에디터에서 빨간 줄이 뜨는데, 새 글 작성할 땐 서버 id가 없으니까 그냥 ? 붙여도 될까요?" 프론트엔드 개발을 하다 보면 슬랙이나 코드 리뷰에서 심심치 않게 보게 되는 질문입니다. ... - - - [누가 시키지도 않았는데 번들러 만들기] 4. 소스맵: 번들된 코드에서 원본의 흔적 찾기 - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-04-sourcemap/ - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-04-sourcemap/ - Mon, 02 Mar 2026 15:00:00 GMT - 수천 줄로 합쳐진 번들 파일에서 에러가 나면 어떻게 원본 위치를 찾을까요? 소스맵의 VLQ 인코딩 원리와 magic-string이 변환 이력을 관리하는 방식을 직접 구현하며 이해합니다. - - - [누가 시키지도 않았는데 번들러 만들기] 3. 번들링과 스코프: 파일 합치기의 기술 - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-03-bundling-scope/ - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-03-bundling-scope/ - Sun, 22 Feb 2026 15:00:00 GMT - 단순히 파일을 합치는 것과 번들링은 다릅니다. 변수 충돌을 막기 위한 함수 스코프 전략과 브라우저를 위한 런타임 구현 과정을 깊이 있게 다룹니다. - - - [누가 시키지도 않았는데 번들러 만들기] 2. 코드를 데이터로 보는 법 (AST Graph) - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-02-ast-graph/ - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-02-ast-graph/ - Mon, 16 Feb 2026 15:00:00 GMT - 정규표현식으로 import 문을 찾으려다 실패한 경험, 그리고 AST 추상 구문 트리를 통해 코드를 데이터로 바라보는 관점을 소개합니다. 파일 시스템을 그래프로 변환하는 과정을 직접 구현해봅니다. - - - [누가 시키지도 않았는데 번들러 만들기] 0. 프롤로그: 질문이 구현이 되는 순간 - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-00-prologue/ - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-00-prologue/ - Sun, 01 Feb 2026 15:00:00 GMT - 수많은 소스 코드가 어떻게 하나의 결과물로 합쳐질까요? 당연하게 사용하던 번들러의 블랙박스를 열고, 직접 손으로 구현하며 그 답을 찾아봅니다. - - - [누가 시키지도 않았는데 번들러 만들기] 1. 개념과 도구: 번들러의 등장 배경 - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-01-concept/ - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-01-concept/ - Sun, 01 Feb 2026 15:00:00 GMT - 코드를 번들링해야 하는 기술적 이유와 자바스크립트 모듈 시스템의 발전 과정을 살펴봅니다. 또한 번들러 구현의 기반이 되는 Magic String 라이브러리를 소개합니다. - - - 결제 시스템 리팩토링: if문 지옥에서 디자인 패턴(Factory, Adapter)으로 탈출하기 - https://blog.sangwook.dev/posts/payment-system-architecture/ - https://blog.sangwook.dev/posts/payment-system-architecture/ - Fri, 23 Jan 2026 15:00:00 GMT - "만약 내일 당장 '프랑스'가 서비스 국가로 추가된다면? 그리고 한국에서 '사업자 유형'에 따라 결제 수단이 달라져야 한다면?" 이 질문들이 우리 팀의 결제 시스템 설계를 완전히 바꿔놓았습니다. --- 🎭 Prologue: "팀장님의 무리한(?) 요구" 어느 날 오후, 코드 리뷰 중에... - - - 2025 회고: 글 33개, PR 38회, 발표 3회로 '보여주는 개발자'가 되다 - https://blog.sangwook.dev/posts/2025-retrospect/ - https://blog.sangwook.dev/posts/2025-retrospect/ - Sat, 20 Dec 2025 15:00:00 GMT - 2025 회고: 글 33개, PR 38회, 발표 3회로 '보여주는 개발자'가 되다 2025년은 "숨어서 잘하는 개발자" 에서 "보여주고 나누는 개발자" 로 방향을 튼 해였습니다. 시작점은 2024년 12월 23일, 한 개발자의 피드백이었습니다. "평소 기술 관련 답변을 잘 해주시는데, ... - - - 2025 Teoconf 발표 후기 - https://blog.sangwook.dev/posts/2025-teoconf-presentation/ - https://blog.sangwook.dev/posts/2025-teoconf-presentation/ - Wed, 10 Dec 2025 15:00:00 GMT - 🎤 발표 후기: ‘내가 하고 싶은 말’ 대신 ‘청중이 가져갈 한 문장’을 찾기까지 이번 테오콘 발표는 내게 하나의 도전이었다. 디자인 시스템 배포라는, 나에게 깊은 경험이지만 청중에게는 다소 생소할 수 있는 주제를 어떻게 풀어낼 것인가. 그리고 그 과정에서 “발표는 기술을 나열하는 자... - - - 하루 만에 끝날 줄 알았던 디자인 시스템 배포가 3주 걸린 이유 - https://blog.sangwook.dev/posts/npm-deploy-series-0-prologue/ - https://blog.sangwook.dev/posts/npm-deploy-series-0-prologue/ - Sat, 29 Nov 2025 15:00:00 GMT - 하루 만에 끝날 줄 알았던 NPM 배포가 3주 걸린 이유 프롤로그: "별거 아니겠지"의 착각 타팀 기획자님이 내 자리로 다가왔다. "개발자님, 저희 팀에서도 그 디자인 시스템 쓸 수 있을까요? 버튼이랑 인풋 컴포넌트가 정말 예쁘던데..." 당시 디자인 시스템은 완성해둔 참이었다. 모노레... - - - [Typescript로 설계하는 프로젝트] 타입 한 줄로 552개 파일을 2주 만에 안전하게 수정한 방법 - https://blog.sangwook.dev/posts/typescript-project-type-safe-refactor-with-typescript/ - https://blog.sangwook.dev/posts/typescript-project-type-safe-refactor-with-typescript/ - Wed, 05 Nov 2025 15:00:00 GMT - "회원 구조가 바뀌었습니다. 552개 파일을 수정해야 합니다." 보통은 이렇게 됩니다 - 어디를 수정해야 하는지 찾느라 1주 - 수정하다가 놓친 곳 때문에 버그 발생 - 회귀 테스트에 또 1주 - QA에서 엣지 케이스 발견 - 결국 한 달... 하지만 우리는 2주 만에, 사이드 이펙트 ... - - - React 에러 구조 설계: throw만으로 선언적 에러 핸들링 하기 - https://blog.sangwook.dev/posts/react-error-deign/ - https://blog.sangwook.dev/posts/react-error-deign/ - Mon, 13 Oct 2025 15:00:00 GMT - 0. 프롤로그 throw를 보던중 문득 깨달았다. typescript try { throw new Error('error'); } catch (error) { throw error; // 상위로 전파된다 } 에러는 계층을 따라 전파된다. 그럼 에러 클래스도 계층 구조로 설계할 수 있지 ... - - - 구글 개발자가 인정한 성능 최적화 기여 후기 - AI와 함께한 gemini-cli 오픈소스 여정 - https://blog.sangwook.dev/posts/ai-opensource-contribution/ - https://blog.sangwook.dev/posts/ai-opensource-contribution/ - Sat, 06 Sep 2025 15:00:00 GMT - 구글 개발자에게 인정받은 성능 최적화: gemini-cli 기여 후기 이 글을 읽고 나면 - AI와 협업해서 오픈소스 기여하는 방법을 알게 됩니다 - 성능 최적화 PR이 더 좋은 평가를 받는 이유를 이해합니다 - 구글같은 대기업 프로젝트에 기여하는 전략을 배웁니다 - 실제 머지된 PR ... - - - feconf 2025 발표 후기 - https://blog.sangwook.dev/posts/feconf-2025-lightning-speaker/ - https://blog.sangwook.dev/posts/feconf-2025-lightning-speaker/ - Mon, 01 Sep 2025 15:00:00 GMT - 시작 마이크를 잡는 순간 정말 내가 말해도 되는건가? 나 해도되는건가? 이 생각이 든 건 몇 달 전부터였다. 어느 모임에서 feconf 2024 라이트닝 연사자 분을 만나게 되었다. 재미있게 이야기 하던 도중 나에게 날아든 질문이 있었다. "상욱님도 이거 잘 하실 수 있을 것 같아요! ... - - - 4시간 만에 Node.js PR 승인받기 - https://blog.sangwook.dev/posts/nodejs-contribution/ - https://blog.sangwook.dev/posts/nodejs-contribution/ - Sat, 09 Aug 2025 15:00:00 GMT - 4시간 만에 Node.js PR 승인받기 AI 페어 프로그래밍으로 오픈소스 진입 장벽 낮추기 “무조건 Node.js에 내 코드를 넣고 말겠다!” 오픈소스 기여가 점점 재미있어지고, 자신감도 차오르던 시기였다. 하지만 매일같이 이슈를 살펴봐도 여전히 모르는 부분이 많았다. C++ 코드가 ... - - - Next.js 오픈소스 기여: 2번 실패 후 성공 후기 - https://blog.sangwook.dev/posts/nextjs-contributor/ - https://blog.sangwook.dev/posts/nextjs-contributor/ - Mon, 04 Aug 2025 15:00:00 GMT - Next.js 오픈소스 기여: 2번 실패 후 성공 후기 들어가며 "띠링" 새벽 2시, 내 핸드폰에 또 다른 GitHub 알림이 울렸다. 발신자: vercel/next.js [[제목] : Re:[vercel/next.js] Fix remote pattern (80294) (PR 80428... - - - Context API를 활용한 DropZone 구현하기 - https://blog.sangwook.dev/posts/react-component-context-api-dropzone/ - https://blog.sangwook.dev/posts/react-component-context-api-dropzone/ - Tue, 29 Jul 2025 15:00:00 GMT - [React Component] Context API를 활용한 DropZone 구현하기 평소처럼 Mantine의 Dropzone을 사용하고 있었는데, 문득 내부 구현이 궁금해졌습니다. 어떻게 이렇게 깔끔한 API를 제공할 수 있을까? tsx // Mantine Dropzone 사용 중.... - - - Type Guard를 활용한 여러가지 Button 구현하기 - https://blog.sangwook.dev/posts/react-component-type-guard-button/ - https://blog.sangwook.dev/posts/react-component-type-guard-button/ - Sun, 29 Jun 2025 15:00:00 GMT - [React Component] Type Guard를 활용한 여러가지 Button 구현하기 드디어 디자인 시스템 프로젝트가 시작되었습니다! 팀에서 가장 먼저 구현하기로 한 컴포넌트는 Button입니다. 디자인 시스템에서 Button은 특별합니다. 가장 많이 사용되고, 가장 다양한 형태를... - - - 15줄에서 2줄로: useSyncExternalStore 기반 React Toast 시스템 설계법 - https://blog.sangwook.dev/posts/react-component-toast/ - https://blog.sangwook.dev/posts/react-component-toast/ - Sun, 29 Jun 2025 15:00:00 GMT - 들어가며 안녕하세요, 여러분! 프론트엔드 개발자라면 누구나 한 번쯤 만들어보는 토스트 UI. 간단해 보이지만, 막상 구현하다 보면 "이걸 어떻게 앱 어디서든 쉽게 호출하지?", "종류별로 다른 스타일은 어떻게 관리하지?" 같은 고민에 빠지게 됩니다. 최근 mantine의 토스트 컴포넌트... - - - 개발자에서 기여자로: 기술 블로그와 오픈소스가 바꾼 나의 2025년 상반기 - https://blog.sangwook.dev/posts/2025-mid-year-review/ - https://blog.sangwook.dev/posts/2025-mid-year-review/ - Mon, 16 Jun 2025 15:00:00 GMT - 들어가며 2025년 상반기를 돌아보니, 가장 크게 변화한 것은 "나만 알고 있던 지식을 세상과 나누기 시작 했다"는 점이다. 그동안 개발자로서 쌓아온 경험들과 고민을 글로 정리하고, 오픈소스에 기여 하면서 진정한 의미의 성장을 경험한 상반기였다. --- 🌟 기술 블로그: 지식 공유의 ... - - - [Typescript로 설계하는 프로젝트] "같은 로직 또 복사했어요?" Domain 모델로 책임 분리하기 - https://blog.sangwook.dev/posts/typescript-project-domain-design/ - https://blog.sangwook.dev/posts/typescript-project-domain-design/ - Sat, 14 Jun 2025 15:00:00 GMT - 들어가며 오후 4시, 또 다시 울리는 슬랙 알림... [기획자]: "저번에 만든 사용자 상태 로직 잘 쓰고 있어요! 그런데 이번엔 사용자가 특정 액션을 할 수 있는지 검증하는 로직도 추가해 주세요." [나]: "네, 어떤 검증 로직인가요?" [기획자]: "사용자가 글을 작성할 수 있는지... - - - [Typescript로 설계하는 프로젝트] "원래 있던 기능이니 금방 하시죠?" 당하지 않는 Service Layer 설계 전략 - https://blog.sangwook.dev/posts/typescript-project-service-design/ - https://blog.sangwook.dev/posts/typescript-project-service-design/ - Sat, 07 Jun 2025 15:00:00 GMT - 들어가며 겨우 백엔드의 요청을 쳐내고 다시 피곤함에전 모습으로 테스크를 마무리하려는 순간 이번엔 제 슬랙이 울립니다. [기획자]: "급하게 기획이 바뀌어서요. 이거 프론트에서 추가로 수정해 주셔야 할 것 같아요. 아직 마무리 다 안 하신 거 맞죠?" [나]: "네 아직 마무리 안 했어요... - - - [Typescript로 설계하는 프로젝트] "원래 있던 기능이니 금방 하시죠?" 당하지 않는 Service Layer 설계 전략 With Di - https://blog.sangwook.dev/posts/typescript-project-service-di-design/ - https://blog.sangwook.dev/posts/typescript-project-service-di-design/ - Sat, 07 Jun 2025 15:00:00 GMT - 들어가며 겨우 백엔드의 요청을 쳐내고 다시 피곤함에전 모습으로 테스크를 마무리하려는 순간 이번엔 제 슬랙이 울립니다. [기획자]: "급하게 기획이 바뀌어서요. 이거 프론트에서 추가로 수정해 주셔야 할 것 같아요. 아직 마무리 다 안 하신 거 맞죠?" [나]: "네 아직 마무리 안 했어요... - - - [Typescript로 설계하는 프로젝트] Type 설계의 시작: 견고한 서버 API Type 설계하기 - https://blog.sangwook.dev/posts/typescript-project-api-design/ - https://blog.sangwook.dev/posts/typescript-project-api-design/ - Sat, 31 May 2025 15:00:00 GMT - 들어가며 피곤에 쩔은 모습으로 하나의 테스크를 마무리 하는 순간 백엔드 개발자가 다가옵니다. "죄송하지만 이번에 만든 api 중에 하나의 리스폰스가 변동 될 것 같습니다." "User로 정의한 스키마 중에 name이 빠질 것 같아요." 순간 머릿속에서 여기저기 대강 흩어져 있는 User... - - - [Typescript로 설계하는 프로젝트] Type 설계의 시작: 견고한 서버 API Type 설계하기 With DI - https://blog.sangwook.dev/posts/typescript-project-api-di-design/ - https://blog.sangwook.dev/posts/typescript-project-api-di-design/ - Sat, 31 May 2025 15:00:00 GMT - 들어가며 피곤에 쩔은 모습으로 하나의 테스크를 마무리 하는 순간 백엔드 개발자가 다가옵니다. "죄송하지만 이번에 만든 api 중에 하나의 리스폰스가 변동 될 것 같습니다." "User로 정의한 스키마 중에 name이 빠질 것 같아요." 순간 머릿속에서 여기저기 대강 흩어져 있는 User... - - - [Typescript로 설계하는 프로젝트] 당신의 Type, 어디까지 연결되어 있나요? - https://blog.sangwook.dev/posts/typescript-project-design/ - https://blog.sangwook.dev/posts/typescript-project-design/ - Sun, 04 May 2025 15:00:00 GMT - [타입으로 설계하는 프로젝트] 당신의 Type, 어디까지 연결되어 있나요? 들어가며 플래닝이 끝나고 난 뒤 저에게 주어진 테스크를 살펴 봅니다. "뭐시기 뭐시기 기능 수정 및 삭제" 큰 기능 아니니 그냥 지워도 될거라는 저의 생각은 조만간 큰 버그를 가져왔습니다. 테스트 서버에 올려보니... - - - pnpm 10 업그레이드 후 ESLint 설정이 사라졌어요?! (feat. 호이스팅) - https://blog.sangwook.dev/posts/pnpm-eslint-not-working/ - https://blog.sangwook.dev/posts/pnpm-eslint-not-working/ - Wed, 30 Apr 2025 15:00:00 GMT - 0. 프롤로그 pnpm 9 → 10 업그레이드 후 monorepo에서 eslint가 동작하지 않는 문제를 겪은 경험을 공유 합니다. --- 1. 상황설명 저희 회사는 pnpm을 패키지 매니저로 사용하고 있습니다. 최근 pnpm 9에서 pnpm 10으로 업그레이드를 진행했습니다. 업그레이... - - - 오픈소스 첫 발걸음: Mantine PR 기여 후기 - https://blog.sangwook.dev/posts/first-open-source-contribution/ - https://blog.sangwook.dev/posts/first-open-source-contribution/ - Mon, 21 Apr 2025 15:00:00 GMT - 0. 프롤로그 "내가 자주 사용하는 오픈 소스에 기여 해보고 싶다." 늘 마음 한켠에 있었지만, 다른 사람의 기여 후기를 보거나 기여 방법을 보아도 막막 했습니다. 그러던 중, 회사 프로젝트에서 Slider를 구현해야 할 일이 생겼습니다. 디자이너님께서 전달해주신 피그마 시안을 보자마자... - - - 🚨3분만에 Next.js 서비스 장애 대응 대응하기: GitHub Actions + AWS ECS + CodeDeploy 롤백 시스템 - https://blog.sangwook.dev/posts/aws-ecs-rollback/ - https://blog.sangwook.dev/posts/aws-ecs-rollback/ - Wed, 02 Apr 2025 15:00:00 GMT - 0. 프롤로그 이번글에서는 지난번까지 구축한 ECS 환경에서, 오류 발생 시 애플리케이션을 안정적으로 롤백하는 방법에 대해 다뤄보겠습니다. 특히 GitHub Actions, AWS CodeDeploy를 활용하여 자동화된 배포 및 롤백 프로세스를 구현하는 방법을 중심으로 설명드릴 예정입니... - - - ecs와 code deploy를 활용한 next.js 배포하기 - https://blog.sangwook.dev/posts/next-js-ecs-deploy/ - https://blog.sangwook.dev/posts/next-js-ecs-deploy/ - Mon, 31 Mar 2025 15:00:00 GMT - 0. 프롤로그 이전에는 next.js의 standalone과 turborepo의 --docker 옵션을 활용한 도커라이징 하는 방법을 정리하였습니다. 이번에는 aws의 ecs를 통해 컨테이너관리를 하고 code deploy를 통해 배포 하는 방법에 대해서 정리 해보겠습니다. --- 1.... - - - Turborepo 에서 next.js 도커라이징 하기 - https://blog.sangwook.dev/posts/turborepo-next.js-docker/ - https://blog.sangwook.dev/posts/turborepo-next.js-docker/ - Fri, 21 Mar 2025 15:00:00 GMT - 0. 프롤로그 이 글은 뮤즈라이브에서 웹 서비스 3개를 모노레포 구조에서 Turborepo의 공식 문서를 참조하여 Next.js의 standalone 모드와 Docker를 활용한 모노레포 환경 설정 및 최적화 방법을 설명합니다. 목표 - Next.js standalone 모드 설명 - ... - - - Next.js로 우아하게 Error 핸들링하기 - https://blog.sangwook.dev/posts/nextjs-error/ - https://blog.sangwook.dev/posts/nextjs-error/ - Sun, 02 Mar 2025 15:00:00 GMT - 0. 프롤로그 이전까지는 javascript의 try catch과 React의 ErrorBoundary로 error 객체의 전파와 핸들링하는 방법에 대해 알아 보았습니다. <br/이번글에서는 Next.js의 error.js와 동작 방법에 대해 알아보겠습니다. --- 1. Next.js ... - - - React로 우아하게 Error 핸들링 하기 - https://blog.sangwook.dev/posts/react-error/ - https://blog.sangwook.dev/posts/react-error/ - Sat, 01 Mar 2025 15:00:00 GMT - 0. 프롤로그 React 애플리케이션에서 예기치 않은 에러는 사용자 경험에 치명적인 영향을 미칠 수 있습니다. 이 글에서는 ErrorBoundary와 같은 에러 관리 기법을 바탕으로, 비동기 코드에서 발생하는 에러를 어떻게 처리하고, 의도적인 에러와 의도하지 않은 에러를 구분하여 다루는... - - - javascript로 우아하게 Error 핸들링하기 - https://blog.sangwook.dev/posts/javascript-error/ - https://blog.sangwook.dev/posts/javascript-error/ - Wed, 26 Feb 2025 15:00:00 GMT - 프롤로그 이번 글은 JavaScript에서 동기 및 비동기 상황 모두에 대해 에러를 어떻게 처리할 수 있는지에 대해 다룹니다. 에러 처리는 코드의 안정성과 유지보수성에 큰 영향을 미치므로, 명확하고 일관된 패턴을 적용하는 것이 중요합니다. 이 글에서는 기본적인 try-catch 패턴부터... - - - 미들웨어에서 auth 적용하기 - https://blog.sangwook.dev/posts/next-middleware/ - https://blog.sangwook.dev/posts/next-middleware/ - Tue, 25 Feb 2025 15:00:00 GMT - 프롤로그 이번 글에서는 Next.js의 Middleware를 사용하여 사용자 인증 및 역할 기반 라우팅을 구현한 경험을 공유합니다. --- 1. 요구 사항 - Next.js App Route를 사용할 것 - 최상단에서 인증을 처리할 것 - 다른 코드를 수정하지 않을 것 - 캐싱 기능을 ... - - - Panda CSS 1년 사용기 - https://blog.sangwook.dev/posts/panda-css-1year-review/ - https://blog.sangwook.dev/posts/panda-css-1year-review/ - Sun, 16 Feb 2025 15:00:00 GMT - 프롤로그 프로젝트에서 Panda CSS를 도입해 사용해 보면서, 기존의 styled-components나 Tailwind CSS와는 다른 독특한 스타일 작성 방식을 체감할 수 있었습니다. 특히 TypeScript 기반의 타입 안전성, 빌드 타임에 CSS를 정적으로 추출하여 런타임 오버헤... - - - 컴포넌트에 인터렉션 레이어 이쁘게 씌우기 - https://blog.sangwook.dev/posts/adding-interaction-layers-to-components/ - https://blog.sangwook.dev/posts/adding-interaction-layers-to-components/ - Sun, 09 Feb 2025 15:00:00 GMT - 프롤로그 디자인 시스템에서 중요한 목표 중 하나는 일관된 사용자 경험(UX)을 제공하는 것입니다. UI 컴포넌트(버튼, 카드 등)마다 hover, focus, press와 같은 다양한 인터랙션 상태가 있고, 각 상태에서 색상이 어떻게 변화하는지가 사용성에 큰 영향을 미칩니다. 이번 글에... - - - 디자인 시스템 시작해보기 - https://blog.sangwook.dev/posts/design-system-start/ - https://blog.sangwook.dev/posts/design-system-start/ - Sat, 01 Feb 2025 15:00:00 GMT - 프롤로그 디자인 시스템: 우리가 꼭 필요한 이유 새롭게 시작하는 거대한 프로젝트 속에는 또 다른 거대한 과제가 숨어 있었다. 바로 디자인 시스템 구축이었습니다. 이번 프로젝트는 단순히 두 개의 프로젝트를 하나로 합치는 것을 넘어, 디자인 요소 간 불일치로 인해 UX가 저하되고, 개발 및... - - - FSD 간단하게 시작해보기 - https://blog.sangwook.dev/posts/simple-fsd-start/ - https://blog.sangwook.dev/posts/simple-fsd-start/ - Mon, 20 Jan 2025 15:00:00 GMT - 공식홈피를 기반 했지만 제 입맛에 따라 해석 했음을 알려드립니다. 프롤로그 때는 바야흐로 2024년 5월 fsd 아키텍처가 유행하기 시작 했다. 마침 회사의 프로젝트 두개를 하나로 합치는 프로젝트를 시작 하는 나로써는 매우나도 유혹적인 글이었습니다. 하지만 지금 처럼 분석글이 많은 때도... - - - 서버 의존성을 줄여보자 (Feat : 클린 아키텍처) - https://blog.sangwook.dev/posts/reduce-server-dependency-clean-architecture/ - https://blog.sangwook.dev/posts/reduce-server-dependency-clean-architecture/ - Sun, 12 Jan 2025 15:00:00 GMT - 텍스트 기존 클린 아키텍처에서 많이 벗어난 내용이 많습니다. 감안하고 봐주시면 감사하겠습니다. 프롤로그 백엔드 개발자로 시작했지만, 프론트엔드에서 아키텍처 고민을 시작하게 된 이유 저는 자바/스프링으로 커리어를 시작 했습니다. 처음 만든 포트폴리오도 스프링mvc를 사용한 웹사이트 였습니... - - - 도전과 성장, 그리고 배움으로 가득 찬 2024년 회고 - https://blog.sangwook.dev/posts/2024-retrospect/ - https://blog.sangwook.dev/posts/2024-retrospect/ - Sun, 22 Dec 2024 15:00:00 GMT - 도전, 성장, 배움: 2024년 회고 --- 1분기 (13월): 변화의 시작, 역할의 확장 Keep 2024년 초, 팀 내부적으로 큰 변화가 있었습니다. 예상치 못한 시점에 중요한 동료들이 떠나며 공백이 발생했고, 이에 따라 저에게 더 많은 책임과 역할이 주어졌습니다. 이러한 변화 속에... - - - \ No newline at end of file diff --git a/apps/blog/web/public/search-index.json b/apps/blog/web/public/search-index.json deleted file mode 100644 index 03372568..00000000 --- a/apps/blog/web/public/search-index.json +++ /dev/null @@ -1,423 +0,0 @@ -[ - { - "slug": "typescript-domain-modeling-without-optional", - "title": "[Typescript로 설계하는 프로젝트] id?: string을 버려라. 상태가 다르면 타입도 달라야 한다.", - "date": "2026-03-16", - "excerpt": "1. 프롤로그: 우리가 숨 쉬듯 작성하는 \"거짓말\" 팀원: \"OO님, Post 타입에서 id가 없다고 에디터에서 빨간 줄이 뜨는데, 새 글 작성할 땐 서버 id가 없으니까 그냥 ? 붙여도 될까요?\" 프론트엔드 개발을 하다 보면 슬랙이나 코드 리뷰에서 심심치 않게 보게 되는 질문입니다. ...", - "tags": [ - "TypeScript", - "Architecture", - "Data Modeling" - ], - "series": "[Typescript로 설계하는 프로젝트]", - "contentPreview": "1. 프롤로그: 우리가 숨 쉬듯 작성하는 \"거짓말\" 팀원: \"OO님, Post 타입에서 id가 없다고 에디터에서 빨간 줄이 뜨는데, 새 글 작성할 땐 서버 id가 없으니까 그냥 ? 붙여도 될까요?\" 프론트엔드 개발을 하다 보면 슬랙이나 코드 리뷰에서 심심치 않게 보게 되는 질문입니다. 저 역시 예전에는 빠른 기능 구현을 위해 무심코 ?를 붙이며 타입 에러를 '지우는 데' 급급했던 시절이 있었습니다. 십중팔구 이런 타입을 작성해 보셨을 겁니다. 당장 에러는 안 나니 편합니다. 하지만 이 작은 ? 하나 때문에 우리는 프로젝트 내내 고통받습니다. 분명히 DB에서 방금 조회해 온 글이라 100% ID가 존재하는데도, 타입스크립트는 \"ID가 없을 수도 있잖아?\" 라며 끊임없이 딴지를 겁니다. 결국 우리는 울며 겨자 먹기로 컴포넌트 곳곳에 if (post.id)나 post.id! 같은 무의미한 방어 코드를 도배하게 되죠. 코드는 지저분해지고, 개발자의 피로도는 급증합니다. 왜 이런 일이 발생할까요? 우리가 타입스크립트에게 \"도메인의 현실\"을 제대로 알려주지 않고 거짓말을 했기 때문입니다. --- 2. 왜 프론트엔드에 도메인 모델링이 필요한가 '도메인 모델링'이라고 하면 보통 백엔드나 DDD의 영역으로 생각하기 쉽습니다. 하지만 잠깐 생각해 봅시다. 사용자의 행동 흐름을 가장 충실하게 코드로 표현해야 하는 곳이 어디인가요? 바로 프론트엔드입니다. 사용자는 글을 '작성'하고, '저장'하고, '수정'하고, '삭제'합니다. 이 모든 흐름에서 데이터의 상태는 끊임없이 변합니다. 그런데 우리가 이 상태 변화를 타입으로 제대로 표현하지 않으면, 결국 런타임에서 undefined 에러로 돌아옵니다. 도메인 모델링은 유비쿼터스 언어, 엔티티 설계, 바운디드 컨텍스트 정의 등 넓은 영역을 포괄합니다. 하지만 그 첫 번째 원칙은 상태를 타입으로 정확히 표현하는 것 입니다. 이 글에서는 바로 그 첫걸음에 집중합니다. 우리의 비즈니스 규칙을 가만히 들여다봅시다. 1. 작성 중인 글: 제목과 내용만 있습니다. ID는 절대 없습니다. 2. 발행된 글: 서버에 안전하게 저장되었습니다. 반드시 고유한 ID를 가집니다. 즉, 이 도메인에서 \"ID가 생겼다\" 는 것은 단순히 데이터에 문자열 필드 하나가 추가된 것이 아닙니다. 객체의 신분이 '임시'에서 '정식'으로 완전히 바뀌었음을 의미합니다. 그런데 우리는 귀찮다는 이유로 이 완전히 다른 두 가지 상태를 Post라는 하나의 타입에 억지로 욱여넣고, id?: string으로 퉁쳐버린 겁니다. --- 3. Tagged Type: 상태를 타입으로 증명하기 이 문제를 해결하는 타입스크립트의 공식 패턴이 있습니다. 바로 Tagged Type, 또는 Discriminated Union 이라고 불리는 패턴입니다. 핵심 아이디어는 간단합니다. 💡 모든 상태가 공유하는 하나의 리터럴 속성(Tag) 을 만들고, 그 값으로 상태를 식별하자. 중복되는 코드는 BasePost로 깔끔하게 묶어내고, status라는 태그(Tag) 속성으로 상태를 명확히 " - }, - { - "slug": "no-one-asked-library-bundler-04-sourcemap", - "title": "[누가 시키지도 않았는데 번들러 만들기] 4. 소스맵: 번들된 코드에서 원본의 흔적 찾기", - "date": "2026-03-03", - "excerpt": "수천 줄로 합쳐진 번들 파일에서 에러가 나면 어떻게 원본 위치를 찾을까요? 소스맵의 VLQ 인코딩 원리와 magic-string이 변환 이력을 관리하는 방식을 직접 구현하며 이해합니다.", - "tags": [ - "bundler", - "javascript", - "sourcemap", - "vlq", - "magic-string", - "security" - ], - "series": "bundler", - "contentPreview": "4. 소스맵: 번들된 코드에서 원본의 흔적 찾기 \"에러 위치: bundle.js 2847번째 줄\" 지난 편(Step 3. 번들링과 스코프)에서 우리는 드디어 파일을 하나로 합치는 데 성공했습니다. 수십 개의 파일이 IIFE 안에 질서 정연하게 들어가고, 브라우저에서도 정상적으로 실행됩니다. 그런데 잠깐. 실제 프로젝트에서 이 번들 파일을 배포했다고 상상해 봅시다. 운영 중에 에러가 납니다. 브라우저 콘솔이 이렇게 말합니다. bundle.js 2847번째 줄. 여러분이 작성한 수십 개의 원본 파일 중 어디에 해당하는 코드일까요? 그 파일의 몇 번째 줄일까요? 번들러가 파일을 합치는 과정에서 원본의 행과 열 정보는 완전히 뒤섞입니다. 소스맵이 없다면, 이 에러를 디버깅하는 것은 사실상 불가능에 가깝습니다. 이번 편에서는 소스맵의 원리를 파헤치고, 우리 번들러에 직접 구현해보겠습니다. --- 1. 소스맵이란: \"번들 좌표 → 원본 좌표\" 변환표 소스맵을 가장 쉽게 설명하자면 좌표 변환표입니다. 이 변환표가 .map 파일 형태로 번들 파일과 함께 배포됩니다. 브라우저 DevTools는 이 파일을 읽어서, 에러 위치를 자동으로 원본 파일 기준으로 표시해 줍니다. 실제 .map 파일을 열어보면 이런 모양입니다. sources는 원본 파일 목록입니다. sourcesContent에는 원본 파일의 코드가 통째로 들어갑니다. 구현 코드의 includeContent: true 옵션이 켜지면 채워지는 필드입니다. 소스 파일이 없는 환경에서도 디버깅이 가능해지지만, .map 파일에 소스 코드 전체가 포함되어 파일 크기가 크게 늘고 소스가 그대로 노출된다는 트레이드오프가 있습니다. 그리고 mappings는... 외계어처럼 보이는 암호문입니다. 이 mappings 필드가 소스맵의 핵심입니다. 여기에 모든 좌표 변환 정보가 압축되어 있습니다. 이걸 이해하려면 VLQ를 알아야 합니다. --- 2. magic-string의 진짜 목적 잠깐, 본론으로 들어가기 전에 한 가지 물어보겠습니다. 우리는 1편부터 magic-string이라는 라이브러리를 써왔습니다. 단순히 \"문자열을 덮어쓰는 도구\" 로만 알고 있었죠. 그런데 왜 굳이 String.replace()나 정규식을 쓰지 않고 이 라이브러리를 선택했을까요? magic-string의 진짜 목적은 소스맵 생성입니다. 일반 문자열 치환은 \"무엇이 바뀌었는지\" 를 기억하지 못합니다. 하지만 magic-string은 모든 변환 작업의 이력을 내부에 쌓아둡니다. overwrite(start, end, newText)를 호출할 때마다, magic-string은 내부적으로 이런 기록을 남깁니다. \"원본 코드의 0번 인덱스부터 32번 인덱스까지가 'const { Button } = require(1);'로 교체되었다\" 이 이력이 쌓이면 쌓일수록, magic-string은 나중에 \"원본의 어느 위치가 결과물의 어느 위치에 해당하는지\" 역산할 수 있게 됩니다. --- 3. VLQ: mappings 가 외계어인 이유 이제 그 암호문으로 돌아" - }, - { - "slug": "no-one-asked-library-bundler-03-bundling-scope", - "title": "[누가 시키지도 않았는데 번들러 만들기] 3. 번들링과 스코프: 파일 합치기의 기술", - "date": "2026-02-23", - "excerpt": "단순히 파일을 합치는 것과 번들링은 다릅니다. 변수 충돌을 막기 위한 함수 스코프 전략과 브라우저를 위한 런타임 구현 과정을 깊이 있게 다룹니다.", - "tags": [ - "bundler", - "javascript", - "iife", - "scope", - "cjs", - "ast" - ], - "series": "bundler", - "contentPreview": "3. 번들링과 스코프: 파일 합치기의 기술 \"지도는 완성됐다. 이제 길을 닦을 차례다.\" 지난 시간(Step 2. 코드를 데이터로 보는 법), 우리는 코드를 데이터 로 변환하고, 파일들 사이의 복잡한 관계를 그래프 로 그려냈습니다. 이제 우리 손에는 프로젝트의 모든 파일 정보가 담긴 '지도' 가 쥐어져 있습니다. 이제 남은 건 하나입니다. 이 흩어진 파일 조각들을 모아서, 브라우저가 실행할 수 있는 단 하나의 결과물 로 만드는 것입니다. --- 1. 그냥 텍스트로 합치면 안 되나요? 가장 단순하게 생각해봅시다. 번들링이란 결국 파일을 합치는 것이니, 리눅스의 cat 명령어처럼 파일 내용을 순서대로 이어 붙이면 되지 않을까요? 이 두 파일을 합쳐서 브라우저에서 실행해 봅니다. 결과는 어떨까요? ❌ Uncaught SyntaxError: Identifier 'name' has already been declared 처참한 실패입니다. 파일이 나뉘어 있을 때는 각자의 스코프가 보장되었지만, 하나로 합쳐지는 순간 모든 변수가 전역 스코프에 노출되면서 충돌이 발생하기 때문입니다. 이것이 바로 번들러가 단순히 파일을 이어 붙이는 것과 다른 점입니다. 번들러의 첫 번째 임무는 \"각 모듈의 독립적인 스코프를 지켜주는 것\" 입니다. --- 2. 해결책: 함수로 벽 세우기 자바스크립트에서 변수를 가두는 가장 확실한 방법은 무엇일까요? 바로 함수 입니다. 우리는 모듈의 코드를 즉시 실행 함수 로 감싸서, 외부와 격리된 스코프를 만들어줄 것입니다. 🏗️ Before & After [Before: 충돌하는 코드] [After: 평화를 되찾은 코드] 이제 변수 name은 각자의 함수 안에 갇혔습니다. 아무리 많은 파일을 합쳐도 변수 이름이 겹칠 걱정은 없습니다. 💡 기술적 배경 이 방식은 Webpack 13 버전 시절의 \"고전적인\" 방식입니다. 최신 도구들(Rollup, Vite)은 성능을 위해 Scope Hoisting 기술을 써서 함수 없이 합치기도 하지만, 모듈 시스템의 본질인 '격리' 를 이해하기에는 이 방식이 가장 직관적입니다. --- 3. 그래서 전체 모양은 어떻게 생겼나요? 개별 파일을 함수로 감싸는 건 알겠습니다. 그럼 이 수십 개의 함수들을 어떻게 엮을까요? 우리는 이 함수들을 객체에 담고, 그 위에서 관리자가 하나씩 꺼내 쓰는 구조를 만들 겁니다. 이제 우리의 목표가 명확해졌습니다. 위쪽의 require 함수를 구현하고, 아래쪽의 모듈을 채워 넣으면 됩니다. --- 4. 브라우저엔 require가 없다 이제 우리는 각 파일을 함수로 안전하게 감쌌습니다. 그런데 문제가 하나 있습니다. 함수 안에서 다른 모듈을 불러오려면 require가 필요한데, 브라우저에는 require가 없습니다. 따라서 번들러는 단순히 파일을 합치는 것뿐만 아니라, Node.js의 모듈 시스템(require, module, exports)을 브라우저에서 흉내 내는 런타임 을 직접 주입해 줘야 합니다. 미션: 런타임 심 만들기 우리가 구현해야 할 런타임 함수는 크게 3가지" - }, - { - "slug": "no-one-asked-library-bundler-02-ast-graph", - "title": "[누가 시키지도 않았는데 번들러 만들기] 2. 코드를 데이터로 보는 법 (AST Graph)", - "date": "2026-02-17", - "excerpt": "정규표현식으로 import 문을 찾으려다 실패한 경험, 그리고 AST 추상 구문 트리를 통해 코드를 데이터로 바라보는 관점을 소개합니다. 파일 시스템을 그래프로 변환하는 과정을 직접 구현해봅니다.", - "tags": [ - "bundler", - "javascript", - "ast", - "graph", - "dfs", - "algorithm" - ], - "series": "bundler", - "contentPreview": "2. 코드를 데이터로 보는 법 (AST Graph) \"코드는 텍스트가 아니다. 트리다.\" 1편에서는 번들러를 왜 만들어야 하는지, 그리고 magic-string이라는 도구를 맛봤습니다. 이제 본격적으로 코드를 분석하고, 여러 파일을 하나로 묶기 위한 준비를 시작해 봅시다. 이번 편의 목표는 \"흩어진 파일들을 찾아내어 하나의 지도로 그리는 것\" 입니다. --- 1. 어디서부터 묶어야 할까? 번들러가 가장 먼저 해야 할 일은 무엇일까요? 바로 \"진입점\" 을 찾는 것입니다. 우리가 작성한 수많은 파일들을 하나로 묶으려면 어떻게 해야 할까요? 무턱대고 폴더의 모든 파일을 합치는 것은 좋은 방법이 아닙니다. 시작점이 되는 파일(보통 index.js나 main.js) 을 읽고, 그 파일이 어떤 다른 파일들을 필요로 하는지(import) 추적해 나가야 합니다. 이것이 바로 의존성 그래프를 그리기 위한 첫 단추입니다. --- 2. 코드는 단순한 텍스트가 아니다 자, 이제 엔트리 파일의 내용을 읽어왔습니다. 그 다음은 파일 내용에서 import ... from ... 구문을 찾아내야 합니다. 왜 정규표현식을 썼을까? 문자열에서 특정 패턴을 찾는 것. 개발자라면 누구나 가장 먼저 떠올리는 도구가 있죠. 바로 정규표현식 입니다. 직관적으로 생각해보면, import 문은 꽤 단순한 패턴을 가지고 있어 보입니다. \"어? 이거 그냥 문자열 검색으로 찾으면 되는 거 아냐?\" 그래서 처음에는 정규표현식을 떠올리게 됩니다. 정규표현식은 강력하고, 빠르고, 무엇보다 구현하기 쉽습니다. 복잡한 파서를 도입하는 것보다 String.match() 한 방이면 끝날 것 같았죠. --- 3. 정규표현식은 파서가 아니다 예외 케이스 하지만 코드가 조금만 복잡해져도 정규표현식은 무력해집니다. 정규표현식은 문맥을 모릅니다. 주석인지, 문자열인지 구분하지 못하고 \"패턴이 맞네? 가져와!\" 라고 외칠 뿐입니다. 결국 우리는 엉뚱한 파일을 import 하려고 시도하다가 에러를 뿜어내는 번들러를 마주하게 됩니다. 결론: 코드를 단순한 텍스트로 처리하려다간 큰코다칩니다. 구조로 봐야 합니다. --- 4. 도구 1: AST - 코드를 해부하다 그래서 등장하는 도구가 바로 AST(Abstract Syntax Tree, 추상 구문 트리) 입니다. 이름을 하나씩 뜯어보면 이렇습니다. - Abstract: 세미콜론, 괄호, 공백 같은 표면적인 문법 요소는 버리고, 의미만 남긴다는 뜻입니다. - Syntax: 코드의 문법적 구조 — 변수 선언인지, 함수 호출인지, import 문인지를 구분합니다. - Tree: 결과물이 부모-자식 관계를 가진 트리 구조라는 뜻입니다. 결국 AST란, 우리가 작성한 코드를 컴퓨터가 이해하기 쉬운 트리 형태의 데이터 구조로 바꿔놓은 것입니다. 사실 AST는 번들러만의 도구가 아닙니다. ESLint가 코드 규칙을 검사할 때, Prettier가 코드를 포맷팅할 때, Babel이 최신 문법을 변환할 때 — 모두 AST를 기반으로 동작합니다. 이번 편에서 AST를 다루는 관점을 익" - }, - { - "slug": "no-one-asked-library-bundler-00-prologue", - "title": "[누가 시키지도 않았는데 번들러 만들기] 0. 프롤로그: 질문이 구현이 되는 순간", - "date": "2026-02-02", - "excerpt": "수많은 소스 코드가 어떻게 하나의 결과물로 합쳐질까요? 당연하게 사용하던 번들러의 블랙박스를 열고, 직접 손으로 구현하며 그 답을 찾아봅니다.", - "tags": [ - "bundler", - "library", - "build", - "tooling", - "javascript", - "architecture" - ], - "series": "bundler", - "contentPreview": "0. 프롤로그: 질문이 구현이 되는 순간 이전에 작성한 하루 만에 끝날 줄 알았던 디자인 시스템 배포가 3주 걸린 이유 에서는 \"패키지를 배포하는 과정\" 그 자체에 집중했습니다. 이번에는 시선을 조금 더 안쪽으로 돌려보려 합니다. 바로 배포물이 만들어지는 생성 과정 입니다. 배포는 성공적으로 마쳤지만, 정작 결과물이 어떤 원리로 만들어지는지 제대로 이해하지 못한 채 도구에만 의존하고 있다는 의문이 들었습니다. \"남들이 다 쓰니까\", \"이게 표준이라니까\" 라며 무심코 넘겼던 설정값들이 실제로는 번들러 내부에서 어떤 판단을 내리게 만드는 걸까요? --- STEP 1: 당연한 것에 던지는 질문 npm 배포 과정을 정리하면서 계속해서 들었던 질문들이 있습니다. 이 질문들이 이번 시리즈의 기준이 됩니다. - 결합의 원리: 소스 코드는 수십 개인데, 왜 결과물은 하나로 합쳐질까요? 그 경계는 누가, 어떤 기준으로 정하는 걸까요? - 설정의 실체: package.json의 main, module, exports, sideEffects 값들은 번들러의 동작에 어떤 영향을 줄까요? - 의존성의 선별: 모든 의존성을 번들에 포함해야 할까요? external과 peerDependencies는 어떤 기준으로 분류하는 것일까요? - 트리 쉐이킹: 코드를 직접 실행해보지도 않고, 어떻게 사용하지 않는 코드라고 판단하여 제거할 수 있을까요? 이 시리즈는 이러한 질문들에 대해 이론적인 답변을 찾는 대신, 직접 구현하며 답을 찾아가는 기록입니다. 라이브러리 번들러를 직접 만들어보며 그 블랙박스를 열어보려 합니다. --- STEP 2: \"Tsup 쓰면 되는데요?\" 맞습니다. Tsup, Vite, Turbopack 같은 좋은 도구가 이미 존재합니다. 그런데 굳이 직접 번들러를 만들어보는 이유는 도구의 원리를 이해하기 위해서입니다. 이 과정을 통해 다음 3가지를 얻을 수 있습니다. 1. 에러 메시지 해석 능력 Uncaught ReferenceError, Module not found 에러를 만났을 때, 번들러가 그래프를 그리는 과정을 알면 원인을 파악하기 쉽습니다. 2. 도구에 대한 적응력 Webpack, Rollup, Esbuild, Turbopack 등 도구의 이름은 바뀌어도 Parsing, Graph, Linking이라는 본질적인 아키텍처는 변하지 않습니다. 원리를 알면 새로운 도구를 익히는 데 도움이 됩니다. --- STEP 3: 범위 설정 \"프로덕션 레벨의 번들러\"를 만드는 것이 목표가 아닙니다. 복잡한 기능은 제외하고, 번들러의 본질적인 역할에만 집중합니다. 다루는 것 '간단한 번들러' 를 목표로 다음 5가지를 직접 구현합니다. 1. Resolve: import 경로를 찾아내는 Node.js의 규칙 2. Dependency Graph: 파일을 읽어 AST로 변환하고, 파일 간 관계 연결 3. Transform: magic-string을 활용한 코드 조작 4. Generate: IIFE로 스코프를 격리하여 하나로 병합 5. Sourcemap: 디버깅을 위해 원본과" - }, - { - "slug": "no-one-asked-library-bundler-01-concept", - "title": "[누가 시키지도 않았는데 번들러 만들기] 1. 개념과 도구: 번들러의 등장 배경", - "date": "2026-02-02", - "excerpt": "코드를 번들링해야 하는 기술적 이유와 자바스크립트 모듈 시스템의 발전 과정을 살펴봅니다. 또한 번들러 구현의 기반이 되는 Magic String 라이브러리를 소개합니다.", - "tags": [ - "bundler", - "javascript", - "history", - "esm", - "magic-string" - ], - "series": "bundler", - "contentPreview": "1. 개념과 도구: 번들러의 등장 배경 웹 개발 초기에는 HTML에 여러 개의 태그를 나열하여 자바스크립트를 로드했습니다. 애플리케이션의 규모가 커짐에 따라 이러한 방식은 관리의 어려움과 성능 저하를 야기했고, 이는 '빌드' 과정이 필요한 주된 이유가 되었습니다. 이 글에서는 자바스크립트 모듈 시스템의 발전 과정과 번들러가 필수적인 이유, 그리고 우리가 구현할 번들러의 주요 도구들을 살펴봅니다. --- 모듈 시스템의 발전 1. 전역 스코프 문제 초기 자바스크립트는 파일 간 스코프 구분이 없었습니다. a.js에서 선언한 변수는 전역 객체 window에 할당되어 b.js에서도 접근 및 수정이 가능했습니다. 서로 다른 파일에서 동일한 변수명을 사용할 경우, 나중에 로드된 스크립트가 이전 값을 덮어쓰는 문제가 발생했습니다. 이를 방지하기 위해 개발자들은 네임스페이스 객체를 사용하거나 복잡한 변수명 규칙을 적용해야 했습니다. 2. IIFE 패턴 전역 스코프 오염을 막기 위해 IIFE 패턴이 널리 사용되었습니다. 함수 스코프를 활용하여 내부 변수를 격리하고, 외부에서 필요한 기능만 명시적으로 노출하는 방식입니다. 우리가 구현할 번들러의 결과물 또한 이 패턴을 사용하여 모듈 간 격리를 보장합니다. 3. CommonJS 2009년 Node.js의 등장과 함께 CommonJS 시스템이 도입되었습니다. 파일 단위의 모듈 개념이 확립되었으나, 브라우저 환경에서는 require 함수가 존재하지 않고 동기 로딩 방식으로 인한 성능 문제가 있어 클라이언트 사이드에서 직접 사용하기에는 제약이 있었습니다. 4. ESM 2015년 ES6, 자바스크립트 공식 모듈 시스템인 ESM이 표준화되었습니다. 브라우저에서도 을 통해 모듈 시스템을 네이티브로 지원하게 되었습니다. --- 번들러의 필요성 최신 브라우저가 ESM을 지원함에도 불구하고 Vite나 Webpack 같은 번들러가 필요한 이유는 다음과 같습니다. 1. 성능 최적화: 수많은 모듈 파일을 개별적으로 로드하면 네트워크 요청 오버헤드가 발생합니다. 번들링을 통해 파일을 하나 또는 소수 로 병합하여 로딩 성능을 개선할 수 있습니다. 2. 생태계 호환성: npm 생태계의 많은 라이브러리는 여전히 CommonJS로 작성되어 있습니다. 번들러는 이를 브라우저가 이해할 수 있는 형태로 변환하고 통합하는 역할을 수행합니다. 우리가 구현할 번들러는 모듈 탐색, 의존성 그래프 구성, 파일 병합 과정을 수행합니다. --- 기반 기술 1: ESM과 정적 분석 우리가 만들 번들러는 ESM 문법을 기반으로 동작합니다. 정적 분석 CommonJS의 require는 런타임에 실행되는 함수이므로 조건부 호출이 가능합니다. 이는 코드를 실행하기 전에는 의존성을 완벽히 파악하기 어렵게 만듭니다. 반면 ESM의 import 구문은 정적입니다. 파일 최상단에 위치해야 하며, 코드를 실행하지 않고도 의존성 관계를 파악할 수 있습니다. 이는 번들러가 의존성 그래프를 정확하게 구성하고, 사용하지 않는 코드를 제거하는 트리 쉐이킹을 구현하는 기반이 됩니다. " - }, - { - "slug": "payment-system-architecture", - "title": "결제 시스템 리팩토링: if문 지옥에서 디자인 패턴(Factory, Adapter)으로 탈출하기", - "date": "2026-01-24", - "excerpt": "\"만약 내일 당장 '프랑스'가 서비스 국가로 추가된다면? 그리고 한국에서 '사업자 유형'에 따라 결제 수단이 달라져야 한다면?\" 이 질문들이 우리 팀의 결제 시스템 설계를 완전히 바꿔놓았습니다. --- 🎭 Prologue: \"팀장님의 무리한(?) 요구\" 어느 날 오후, 코드 리뷰 중에...", - "tags": [ - "TypeScript", - "Design Pattern", - "Refactoring", - "Architecture", - "Zod", - "Clean Code" - ], - "series": "아키텍처", - "contentPreview": "\"만약 내일 당장 '프랑스'가 서비스 국가로 추가된다면? 그리고 한국에서 '사업자 유형'에 따라 결제 수단이 달라져야 한다면?\" 이 질문들이 우리 팀의 결제 시스템 설계를 완전히 바꿔놓았습니다. --- 🎭 Prologue: \"팀장님의 무리한(?) 요구\" 어느 날 오후, 코드 리뷰 중에 팀장님이 툭 던지신 질문 하나가 뇌리를 스쳤습니다. \"이번에 프랑스(France) 런칭 결정됐어. 기존 PayPal이랑 무통장 입금 은 그대로 쓰고, 프랑스 국민 결제인 'Carte Bancaire' 도 추가해야 돼.\" 여기까진 괜찮았습니다. 그런데 덧붙이시더군요. \"아, 그리고 한국(KR) 쪽 로직도 바꿔야 해. 사업자 유형이 추가됐거든. '해당 없음'이면 그냥 기존처럼 Toss 쓰면 되는데, '개인/법인 사업자' 를 선택하면 세금계산서 때문에 '신용카드(Toss)' 랑 '법인계좌 송금(무통장)' 만 허용해야 돼.\" 순간 머릿속이 하얘졌습니다. '국가별 분기도 벅찬데, 국가 안에서 또 조건부 분기라고? if (country === 'KR' && businessType === 'CORPORATE')...' 하지만 대답을 주저했습니다. 직감적으로 알았거든요. \"if문 몇 개 추가\" 가 쌓이고 쌓여서, 나중엔 \"건드리기만 하면 터지는 레거시 코드\" 가 된다는 것을요. 그래서 결심했습니다. \"복잡한 요구사항? 설정과 규칙만 정의하면 끝납니다.\" 라고 자신 있게 말할 수 있는 구조를 만들어보자고요. --- 🛑 1. 평범한 일상: \"if문의 지옥\" (Before) 초기 결제 시스템은 단순했습니다. 하지만 요구사항이 늘어날수록 코드는 스파게티가 되어갔습니다. 문제점 분석: 1. 관심사의 혼재: '누가 결제 가능한가(Business Rule)'와 '어떻게 결제하는가(Implementation)'가 한 함수에 뒤섞여 있습니다. 2. 높은 결합도: PG사 API가 변경되면 비즈니스 로직까지 영향을 받고, 반대로 비즈니스 규칙이 바뀌면 결제 호출 코드도 수정해야 합니다. 3. 확장성 부족: 조건이 추가될 때마다 if-else 블록을 찾아 헤매야 합니다. --- 💡 2. 해결책: \"변하는 것과 변하지 않는 것을 분리하라\" 무작정 디자인 패턴을 도입하기보다, 문제의 본질을 먼저 파악했습니다. 우리가 겪는 고통의 원인은 \"변하는 것(국가별 규칙, PG사 API)\" 과 \"변하지 않는 것(결제 요청 행위)\" 이 섞여 있기 때문이었습니다. 이를 분리하기 위해 우리는 다음 세 가지 패턴을 적재적소에 배치했습니다. 🛠️ 우리가 선택한 도구들 | 패턴 | 핵심 역할 | 선택 이유 | | :----------- | :------------------------ | :------------------------------------------------------------------------------------------------------------ | | Adapter | 호환성(Compatibility) | 서로 다른 PG사 API를 하나의 인터페이스로 통일하여, 클라이언트" - }, - { - "slug": "2025-retrospect", - "title": "2025 회고: 글 33개, PR 38회, 발표 3회로 '보여주는 개발자'가 되다", - "date": "2025-12-21", - "excerpt": "2025 회고: 글 33개, PR 38회, 발표 3회로 '보여주는 개발자'가 되다 2025년은 \"숨어서 잘하는 개발자\" 에서 \"보여주고 나누는 개발자\" 로 방향을 튼 해였습니다. 시작점은 2024년 12월 23일, 한 개발자의 피드백이었습니다. \"평소 기술 관련 답변을 잘 해주시는데, ...", - "tags": [], - "series": "회고/2025", - "contentPreview": "2025 회고: 글 33개, PR 38회, 발표 3회로 '보여주는 개발자'가 되다 2025년은 \"숨어서 잘하는 개발자\" 에서 \"보여주고 나누는 개발자\" 로 방향을 튼 해였습니다. 시작점은 2024년 12월 23일, 한 개발자의 피드백이었습니다. \"평소 기술 관련 답변을 잘 해주시는데, 회고에는 기술적인 내용이 하나도 없네요.\" 그때 깨달았습니다. 개인브랜딩은 말을 잘하는 게 아니라, 내가 어떤 문제를 어떤 방식으로 해결하는지를 검증 가능한 산출물(글/PR/발표) 로 남기는 일이라는 것. 이 글은 그 전환의 기록입니다. --- 📊 한눈에 보는 2025 | 활동 | 실적 | 주요 성과 | | ----------- | ------------ | ---------------------------- | | 📝 블로그 | 33개 포스트 | 누적 35,000+ 조회수 | | 🔧 오픈소스 | 38회 PR 승인 | Mantine 27회, Node.js 4회 | | 🎤 발표 | 3회 | 쑥떡콘, FEConf 2025, TeoConf | --- 블로그: “어떤 글이 읽히는지”를 확인하다 처음엔 \"내가 이런 글을 써도 될까?\" 가 제일 컸습니다. 하지만 첫 글이 일주일 만에 500회 조회수를 넘기면서(초기 지표), “내가 어떤 고민으로 개발하는지” 를 글로 증명할 수 있겠다는 확신이 생겼습니다. 연말에 조회수 TOP3를 뜯어봤습니다. - 4시간 만에 Node.js PR 승인받기 - 15줄에서 2줄로: useSyncExternalStore 기반 React Toast 시스템 설계법 - React 에러 구조 설계: throw만으로 선언적 에러 핸들링 하기 세 글의 공통점을 분석해보니, 반응 좋은 글에는 패턴이 있었습니다. - 제목은 과정이 아니라 결과가 먼저 보인다. (숫자/시간/변화량처럼 “얼마나?”가 즉시 답이 나는 형태) - 권위 있는 대상 + 나의 실전 경험이 같이 있다. (튜토리얼/이론이 아니라 “충돌/기여/실패/통과”의 신뢰 신호) - 문제 상황이 한 줄로 선명하다. (“이 상황에서 어떻게 했는지”가 제목만 봐도 보인다) - 본문은 왜 쓰게 됐는지 → 기존 방식의 한계 → 선택 → 결과 흐름을 가진다. 개념 중심/정리형 글은 검색 유입은 되지만 반응 지표는 약한 편이었습니다. 그래서 앞으로는 제목을 만들 때 숫자 / 실패·충돌 / 특정 대상 / 변화 한 문장 중 3개 이상을 기본 체크리스트로 두려고 합니다. --- 오픈소스: 레퍼런스를 “외부 검증”으로 만들다 처음 오픈소스에 기여할 때는 \"이런 사소한 것을 PR로 올려도 될까?\" 망설였습니다. 그런데 한 번 머지/승인을 경험하니 관점이 바뀌었습니다. 개인 프로젝트의 결과는 “내가 잘 됐다고 느끼는 것”에 머물 수 있는데, 오픈소스는 외부 리뷰와 릴리스라는 검증이 붙습니다. 2025년에는 특히 아래 경험이 글/발표의 근거가 됐습니다. (링크는 글 끝에 정리했습니다.) - Node.js: util.inspect 숫자 포맷팅 버그 재현 → 테스트 작성 → 수정 → 4시간 만에 PR 승인 - Manti" - }, - { - "slug": "2025-teoconf-presentation", - "title": "2025 Teoconf 발표 후기", - "date": "2025-12-11", - "excerpt": "🎤 발표 후기: ‘내가 하고 싶은 말’ 대신 ‘청중이 가져갈 한 문장’을 찾기까지 이번 테오콘 발표는 내게 하나의 도전이었다. 디자인 시스템 배포라는, 나에게 깊은 경험이지만 청중에게는 다소 생소할 수 있는 주제를 어떻게 풀어낼 것인가. 그리고 그 과정에서 “발표는 기술을 나열하는 자...", - "tags": [], - "series": "회고/2025", - "contentPreview": "🎤 발표 후기: ‘내가 하고 싶은 말’ 대신 ‘청중이 가져갈 한 문장’을 찾기까지 이번 테오콘 발표는 내게 하나의 도전이었다. 디자인 시스템 배포라는, 나에게 깊은 경험이지만 청중에게는 다소 생소할 수 있는 주제를 어떻게 풀어낼 것인가. 그리고 그 과정에서 “발표는 기술을 나열하는 자리가 아니라, 청중이 가져갈 한 문장을 만드는 과정”임을 뒤늦게 깨닫게 되었다. --- 1. 신청 — 아쉬움에서 출발한 도전 FEConf가 끝나고 나에게 큰 아쉬움이 남았다. 준비 과정에서는 20분 넘게 하고도 모자랐던 내용이 실제 발표에서는 10분으로 끝났다. “좀 더 깊게 파고들 수 있었는데…” 이 아쉬움을 해결하고 싶어 테오콘에 신청했다. 그리고 이번에는 디자인 시스템 배포라는, 오랫동안 정리하고 싶던 주제를 발표로 풀어보기로 했다. --- 2. 사전 미팅 — ‘할 이야기가 많다’는 것이 함정 테오와 1:1 사전 미팅을 하며 내 경험을 시간순으로 설명했다. 삽질도 많았고 배운 것도 많았기에 테오도 “이야기 자체는 좋다”고 했다. 문제는 너무 많다는 것. 이때부터 슬슬 불안함이 스며들기 시작했다. 나는 이 경험을 온전히 전달하고 싶었는데, 그 욕심이 발표의 범위를 걷잡을 수 없이 넓히고 있다는 걸 그때는 몰랐다. --- 3. 발표 자료 만들기 — 내용은 40페이지, 피드백은 생각보다 혹독했다 먼저 글을 쓰고 그 글을 슬라이드로 옮기는 방식으로 준비했다. 자연스레 슬라이드는 40페이지가 넘어갔다. 사전 녹화를 제출하고 받은 피드백은 예상보다 훨씬 날카로웠다. - 핵심 메시지가 보이지 않는다 - 설명 흐름이 너무 기술적이다 - 목소리가 너무 차분하다 - 청중과의 연결고리가 약하다 하나하나 곱씹으며 수정했지만 사실 이때도 “어디를 수정해야 하는지” 명확하게 알지 못했다. --- 4. 리허설 — 무엇이 어렵냐는 질문에 답하지 못했다 사전 리허설에서 테오가 물었다. “그럼, 이 발표에서 제일 어려운 부분이 뭐였나요?” 그 질문에 나는 정확하게 답하지 못했다. 그 순간 하나를 깨달았다. “나는 지금 무엇이 문제인지도 모르는 상태로 발표를 준비하고 있었구나.” 다른 스피커들의 발표를 보며 그들은 논리 흐름이 깔끔했고, 청중 집중을 유지하기 위한 장치도 자연스러웠다. 나는 그걸 잘 못하고 있다는 사실만 명확해졌다. 슬라이드는 수정하다보니 어느새 70페이지를 넘어갔고, 당일 아침까지도 수정이 계속됐다. 레이니가 1:1로 피드백을 주었고 그제야 슬라이드의 ‘정렬’이 잡히기 시작했다. --- 5. 발표 당일 — 슬라이드는 일방향이지만, Q&A는 나를 드러낼 수 있었다 발표 당일 리허설을 한 번 더 했다. 긴장은 되었지만 견딜 만했다. 다른 스피커들과 인사하며 분위기도 좋았다. 하지만 세션 2가 시작되자 압박감이 올라왔다. 앞 발표자가 짤로 분위기를 띄우는 걸 보며 “나도 이런 걸 넣을걸…” 하는 생각이 들었다. 그리고 내 순서가 되었다. 준비한 대로 발표를 진행했지만, 솔직히 내가 무슨 말을 했는지 기억이 잘 나지 않는다. 발표가 약 22분 정도로 끝나고 Q&A 시간이 되" - }, - { - "slug": "npm-deploy-series-0-prologue", - "title": "하루 만에 끝날 줄 알았던 디자인 시스템 배포가 3주 걸린 이유", - "date": "2025-11-30", - "excerpt": "하루 만에 끝날 줄 알았던 NPM 배포가 3주 걸린 이유 프롤로그: \"별거 아니겠지\"의 착각 타팀 기획자님이 내 자리로 다가왔다. \"개발자님, 저희 팀에서도 그 디자인 시스템 쓸 수 있을까요? 버튼이랑 인풋 컴포넌트가 정말 예쁘던데...\" 당시 디자인 시스템은 완성해둔 참이었다. 모노레...", - "tags": [ - "NPM", - "디자인 시스템", - "배포", - "Panda CSS", - "tsup", - "빌드" - ], - "series": "design-system-lib-deploy", - "contentPreview": "하루 만에 끝날 줄 알았던 NPM 배포가 3주 걸린 이유 프롤로그: \"별거 아니겠지\"의 착각 타팀 기획자님이 내 자리로 다가왔다. \"개발자님, 저희 팀에서도 그 디자인 시스템 쓸 수 있을까요? 버튼이랑 인풋 컴포넌트가 정말 예쁘던데...\" 당시 디자인 시스템은 완성해둔 참이었다. 모노레포 안에서는 잘 돌아가고 있었다. Button, Input, Card... 약 60개 정도? \"아, 그거요? 별거 아니에요.\" 나는 자신만만하게 대답했다. \"NPM에 올리기만 하면 되니까 하루면 될 것 같은데요?\" 기획자님의 환한 미소가 아직도 기억난다. \"정말요? 그럼 이번 주 안에 가능할까요?\" \"네, 금방이에요!\" --- 그리고 3주가 지났다. 하루라고 했던 작업은 21일이 걸렸다. 그 사이에 나는: - 빌드 도구와 10일을 싸웠고 - 20MB 괴물 패키지를 만들어냈고 - CSS 충돌로 머리를 쥐어뜯었고 - 무한 재귀 배포를 중단시켰다 지금 돌아보면 그날의 나에게 말해주고 싶다. \"별거 아닌 일은 없어. 특히 배포는.\" 그땐 좋아 보였는데... 완벽한 계획 (예상 기간: 1일) 머릿속으로 그린 계획은 완벽했다. - 트리셰이킹 - CSS 번들 - Type 지원 - 배포 문서 - 자동 배포 시스템 \"배포 말고는 이미 잘 되어 있는거니 별 문제 없겠지?\" 과연 이 계획대로 될까? 우리 프로젝트 상황 모노레포 구성 - 신규 프로젝트와 디자인 시스템을 동시에 구현 - 코드 공유와 의존성 관리의 효율성 고려 - 향후 다른 팀으로의 확장 가능성 기술 스택 선택: Mantine + Panda CSS 당시 팀 상황을 고려하면 현실적인 선택이었다: - 개발/디자인 리소스 부족 - 디자인 시스템 구축 경험 부족 - Tailwind 문법에 대한 팀 내 선호도 문제 Mantine의 높은 완성도와 Panda CSS의 유연성이 우리 팀에 적합해 보였다. 현재 프로젝트 구조 디자인 시스템 패키지와 4개의 공통 내부 패키지로 구성. 배포 요구사항 타팀에서 디자인 시스템을 사용하기 위해 충족해야 할 조건들: 1. NPM 패키지 배포: GitHub Packages, 버전 관리, 문서화 2. 외부 설치 가능: 모노레포 외부 서비스에서 손쉬운 설치 3. 환경 호환성: - 타팀 환경: Remix + Tailwind - 우리 환경: Mantine + Panda CSS 4. 내부 패키지 의존성 처리: 4개 내부 패키지 의존성 관리 \"별거 아니겠지\"라고 생각한 1일 예상 작업이 3주간의 여정으로 시작됐다. 1주차: 빌드 지옥편 - \"나는 라이브러리 번들을 몰랐다\" 일단 빌드 부터 해보자! 빌드 도구 선택: tsup 여러 빌드 도구를 검토한 끝에 tsup을 선택했다. tsup을 선택한 이유: - 본인이 라이브러리 배포에 대한 지식이 전무 - 간편한 config → 러닝 커브 낮음 - TypeScript 타입 자동 생성 지원 (.d.ts 파일 자동 생성) - esbuild 기반 → go 기반 가볍고 빠름 - 후처리 파이프라인과 통합 용이 → onSuccess 훅으로 다양하고 편리한 통합 가능 첫 번" - }, - { - "slug": "typescript-project-type-safe-refactor-with-typescript", - "title": "[Typescript로 설계하는 프로젝트] 타입 한 줄로 552개 파일을 2주 만에 안전하게 수정한 방법", - "date": "2025-11-06", - "excerpt": "\"회원 구조가 바뀌었습니다. 552개 파일을 수정해야 합니다.\" 보통은 이렇게 됩니다 - 어디를 수정해야 하는지 찾느라 1주 - 수정하다가 놓친 곳 때문에 버그 발생 - 회귀 테스트에 또 1주 - QA에서 엣지 케이스 발견 - 결국 한 달... 하지만 우리는 2주 만에, 사이드 이펙트 ...", - "tags": [], - "series": "[Typescript로 설계하는 프로젝트]", - "contentPreview": "\"회원 구조가 바뀌었습니다. 552개 파일을 수정해야 합니다.\" 보통은 이렇게 됩니다 - 어디를 수정해야 하는지 찾느라 1주 - 수정하다가 놓친 곳 때문에 버그 발생 - 회귀 테스트에 또 1주 - QA에서 엣지 케이스 발견 - 결국 한 달... 하지만 우리는 2주 만에, 사이드 이펙트 없이 끝냈습니다. 비결은 1년 전 작성한 이 한 줄이었습니다. --- 문제 상황 회원 구조가 바뀌었습니다. 예전에는 항상 ProfileId가 선택되어 있었지만, 이제는 선택하지 않을 수도 있게 되었습니다. --- 문제의 크기 거의 모든 서비스 기능이 영향을 받았습니다. 영향받은 주요 기능 - 콘텐츠 관리 (업로드, 수정, 삭제) - 데이터 조회 (통계, 수익, 리포트) - 권한 관리 (접근 제어, 팀 관리) 이런 코드가 곳곳에 있었습니다: 기존엔 getProfileId()가 항상 string을 보장했습니다. 하지만 이제는 undefined일 수 있게 되었습니다. 옵셔널이 되어야 합니다. 552개 파일을 수정해야 하는 상황. 어떻게 안전하게 해낼 수 있을까요? --- 왜 가능했을까? 1: 도메인 분리의 시작점 처음 코드를 작성할 때, 이렇게 할 수도 있었습니다: 하지만 우리는 이렇게 했습니다: 무엇이 달라졌을까요? string은 그냥 원시 타입입니다. \"문자열\" 이라는 것 외에 아무 의미가 없습니다. 하지만 ProfileId는 다릅니다: - \"이 값은 프로필을 식별하는 ID다\" - \"이 값은 특정 도메인에 속한다\" 코드에 의미 계층을 추가한 것입니다. 이 작은 차이가 대규모 변경을 가능하게 만들었습니다. --- 해결 전략 핵심은 타입 추상화에 있었습니다. 코드 곳곳에 ProfileId 타입이 명시되어 있었기 때문에, 반환 타입만 바꾸면 컴파일러가 수정이 필요한 모든 곳을 알려줄 수 있었습니다. 타입 하나만 바꿨을 뿐인데, 타입스크립트 컴파일러가 수정이 필요한 모든 곳을 찾아냈습니다. --- 왜 가능했을까? 2: 변경 추적 가능한 단위 생성 타입 별칭이 없었다면 어땠을까요? 이 코드의 문제는 의미가 없다는 것입니다. string만 봐서는: - 어떤 string이 ProfileId인지 알 수 없음 - 어떤 string이 UserId인지 알 수 없음 - 나중에 코드를 읽을 때 매번 변수명을 확인해야 함 --- 하지만 ProfileId라는 타입을 만들면: 무엇이 달라지나? 1. 코드 자체가 문서가 됩니다 2. 변경 추적이 가능해집니다 이제 getProfileId()의 반환 타입만 바꾸면: TypeScript 컴파일러가 영향받는 모든 곳을 찾아냅니다: 이 에러들이 수정이 필요한 모든 파일의 위치를 정확히 알려줬습니다. --- 이것이 \"변경 추적 가능한 단위\"를 만든 것입니다. ProfileId 타입 덕분에: 1. 검색: 정확히 관련 코드만 찾음 2. 문서화: 코드 읽을 때 의미가 즉시 파악됨 타입 하나만 바꾸면, 그 변경이 자동으로 전체에 전파되고, 컴파일러가 수정이 필요한 모든 곳을 알려줍니다. 단순히 string이 아니라, ProfileId라는 의미를 부여한 것 " - }, - { - "slug": "react-error-deign", - "title": "React 에러 구조 설계: throw만으로 선언적 에러 핸들링 하기", - "date": "2025-10-14", - "excerpt": "0. 프롤로그 throw를 보던중 문득 깨달았다. typescript try { throw new Error('error'); } catch (error) { throw error; // 상위로 전파된다 } 에러는 계층을 따라 전파된다. 그럼 에러 클래스도 계층 구조로 설계할 수 있지 ...", - "tags": [], - "series": "우아하게 에러 핸들링 하기", - "contentPreview": "0. 프롤로그 throw를 보던중 문득 깨달았다. 에러는 계층을 따라 전파된다. 그럼 에러 클래스도 계층 구조로 설계할 수 있지 않을까? ErrorBoundary에서 instanceof로 잡으려면 되지 않을까? 1. 에러를 어떻게 설계 할 것인가? 1.1. 문제: 모든 에러가 똑같이 보인다 에러가 발생하면? 문제점: ErrorBoundary에서 섹션별 처리 불가, 디버깅 어려움 1.2. 왜 클래스 설계인가? 프롤로그에서 본 계층 구조를 실제로 구현하려면 클래스 상속이 필요하다. 상속 구조의 장점 1. instanceof로 타입 체크 2. 계층적 ErrorBoundary 설계 3. 공통 속성 관리 클래스 상속이 있어야 얕고 넓은 구조를 만들 수 있다. 개선점: instanceof StatsError로 타입 구분 가능, ErrorBoundary 선택적 처리 핵심: try-catch로 Error을 잡아서, 커스텀 에러 클래스로 변환해서 throw 1.3. throw vs return? 에러를 변환하기로 했다. 그런데 질문이 하나 생긴다. \"변환한 에러를 throw 해야 할까, return 해야 할까?\" 나는 throw를 선호한다. 코드 리뷰를 하다 보면, return error 방식에서 자잘한 버그를 너무 자주 봤다. 에러를 return 값으로 넘겼는데 중간에 체크를 빠뜨리거나, 조건문 분기가 복잡해지는 경우가 많았다. throw는 명료하다. 에러가 발생하면 자동으로 전파되고, 중간 계층은 신경 쓸 필요가 없다. 두 가지 선택지 방식 1: throw 방식 2: return error 두 방식 모두 가능하다. 선언적으로 Error을 핸들링하기 위해선 throw가 더 적합하다. 왜 그럴까? 1. 흐름 제어가 간단하다 return error 방식의 문제: 함수 체인의 모든 단계에서 에러를 체크해야 한다. 코드가 길어지고, 실수하기 쉽다. throw 방식의 장점: 에러가 발생하면 자동으로 상위로 전파된다. 일일이 if (error) 체크할 필요 없다. 2. 계층 간 유연한 통합 React 애플리케이션의 계층 구조를 보자: throw를 사용하면: - Component는 에러를 몰라도 된다 (선언적으로 사용) - Hook도 에러 처리 코드가 필요 없다 - API 레이어에서만 에러를 변환 - ErrorBoundary가 자동으로 캐치 핵심: 중간 계층들이 에러를 props나 return으로 전달할 필요 없이, throw만 하면 ErrorBoundary까지 자동으로 전파된다. 3. React ErrorBoundary와의 시너지 React Query + Suspense + ErrorBoundary 조합을 보자: 2. 계층 구조 설계하기 커스텀 에러 클래스를 만들기로 했다. 그럼 어떻게 설계해야 할까? 2.1. Base 클래스: 왜 ApiError인가? 먼저 base 클래스가 필요하다. 왜 Error를 직접 상속하지 않고 ApiError를 만들었을까? JavaScript의 기본 Error 클래스는 message만 있다. 하지만 API 에러는 더 많은 정보가 필요" - }, - { - "slug": "ai-opensource-contribution", - "title": "구글 개발자가 인정한 성능 최적화 기여 후기 - AI와 함께한 gemini-cli 오픈소스 여정", - "date": "2025-09-07", - "excerpt": "구글 개발자에게 인정받은 성능 최적화: gemini-cli 기여 후기 이 글을 읽고 나면 - AI와 협업해서 오픈소스 기여하는 방법을 알게 됩니다 - 성능 최적화 PR이 더 좋은 평가를 받는 이유를 이해합니다 - 구글같은 대기업 프로젝트에 기여하는 전략을 배웁니다 - 실제 머지된 PR ...", - "tags": [], - "series": "open-source", - "contentPreview": "구글 개발자에게 인정받은 성능 최적화: gemini-cli 기여 후기 이 글을 읽고 나면 - AI와 협업해서 오픈소스 기여하는 방법을 알게 됩니다 - 성능 최적화 PR이 더 좋은 평가를 받는 이유를 이해합니다 - 구글같은 대기업 프로젝트에 기여하는 전략을 배웁니다 - 실제 머지된 PR 사례를 통해 구체적인 노하우를 얻습니다 들어가며 \"내 코드를 구글의 프로젝트에 넣을 수 있다니!\" 2025년 6월 25일 gemini-cli가 출시되었습니다. CLI 환경의 AI 도구들이 쏟아져 나오는 요즘, 이 프로젝트가 특별했던 이유는: - JavaScript 기반: 익숙한 기술 스택 - 화제성: 출시 직후부터 관심 집중 - 작은 코드베이스: 아직 분석 가능한 규모 - 개선 여지: 급하게 만들어진 티가 여기저기 보임 - 적극적인 오픈소스: 전세계 개발자들의 참여를 적극 유도 무엇보다 구글러들에게 직접 코드리뷰를 받을 수 있다는 점이 가장 매력적이었습니다. 기여할 것을 찾아보자 설레는 마음으로 코드베이스를 뜯어보기 시작했습니다. ai와 함께 코드베이스를 분석하고 기여할 점을 부탁 하였습니다. ex) 사용했던 프롬프트 User 여기는 gemini-cli 프로젝트예요. 함께 개선할 점을 찾아봐요! --- AI Assistant read-many-files.ts에서 파일 처리가 동기적으로 이뤄지고 있어요. 개선 방향은 아래와 같아요: - for...of 순회를 Promise 목록 기반 병렬 처리로 전환 - detectFileType 함수를 비동기로 변경 --- User 개선할 코드 제안해주고 이게 어떤 이점을 가져오는지 설명해줘 --- AI Assistant (변경 코드 보여주고 설명 하는 중) 이 내용을 보았을 성능관련 기여를 할 수 있다고 생각을 했고 메인테이너의 입장에서는 새로운 기능을 추가하는 PR은 메인테이너 입장에서 고려할 게 많습니다. 프로젝트의 방향성과 맞는지, 다른 기능과 충돌은 없는지, 앞으로 유지보수 비용은 어떨지 등등... 하지만 성능 개선 PR은 빚을 갚아주는 것과 같습니다. 누구도 마다할 이유가 없죠. 프로젝트를 더 건강하게 만드는, 가장 환영받는 기여 중 하나입니다. 하지만 너무 바꿀 범위가 많다고 생각을 했습니다. 그래서 pr을 2개 쪼개어 날리기로 했습니다. 두 번이나 pr을 날릴수도 있고 계획적으로 나만의 로드맵을 그려갈 수 있다고 생각을 했습니다. 1. fileUtils.ts - 개선 2. read-many-files.ts - 병렬처리로 전환 기여 시작 1차 기여: fileUtils.ts 비동기 전환 저 파일안에 있는 detectFileType 만 비동기로 만들어도 되었지만 ai는 나에게 좀 더 몇 가지 개선점을 알려주었습니다. fs.promises 를 붙인 것만으로도 아래와 개선 효과를 볼 수 있다는 걸 ai와 함께 정리 했습니다. 주요 차이점 1. 동기 vs 비동기 처리 - AS-IS: 동기 함수 (function) - TO-BE: 비동기 함수 (async function) 2. 파일 시스템 API - AS-IS: 동기 메" - }, - { - "slug": "feconf-2025-lightning-speaker", - "title": "feconf 2025 발표 후기", - "date": "2025-09-02", - "excerpt": "시작 마이크를 잡는 순간 정말 내가 말해도 되는건가? 나 해도되는건가? 이 생각이 든 건 몇 달 전부터였다. 어느 모임에서 feconf 2024 라이트닝 연사자 분을 만나게 되었다. 재미있게 이야기 하던 도중 나에게 날아든 질문이 있었다. \"상욱님도 이거 잘 하실 수 있을 것 같아요! ...", - "tags": [], - "series": "feconf", - "contentPreview": "시작 마이크를 잡는 순간 정말 내가 말해도 되는건가? 나 해도되는건가? 이 생각이 든 건 몇 달 전부터였다. 어느 모임에서 feconf 2024 라이트닝 연사자 분을 만나게 되었다. 재미있게 이야기 하던 도중 나에게 날아든 질문이 있었다. \"상욱님도 이거 잘 하실 수 있을 것 같아요! 너무 좋은 경험이었어서 꼭 해보셨으면 좋겠어요!\" 신청 마침 스피커 모집이 있었고 크게 고민하지 않고 신청을 했다. 마침 오픈소스의 즐거움을 알아가던 참이었다. 이 메시지를 전달하면 된다는 생각을 가졌기 때문이다. 평소에 글쓰기도 자주 하고 있어 요약본으로 form을 제출했다. 상세 내역은 github 주소에 md 파일로 올려 신청을 했다. 선정 \"됐네?!?!?\" 심장이 떨렸다. 스크롤을 다시 올렸다 내렸다를 반복했다. 하지만 카운트 다운이 시작된 것처럼 바쁘게 움직였다. 준비 일정 5/27일에 선정 결과를 받았고 8/23일에 발표였다. 3번 정도의 사전 리허설이 있었다. 나의 목표는 첫 리허설까지 발표 슬라이드 완성이었다. 그렇게 해야 발표일 전까지 피드백을 받아 수정도 가능할 것 같았다. 초안 작성 관련링크 내용에 대한 고민은 많이 하지 않았다. 이미 전달하고 싶은 이야기는 정했기 때문이다. 가장 큰 걱정은 생각보다 양이 많다는 것이었다. 그래도 열심히 적었다. 정말 하고 싶은 이야기 다 적었다. 일단 적고 줄이는 전략으로 만들기 시작한 것이었다. 슬라이드 작성 이렇게 만든 초안을 슬라이드로 옮기는 것이 문제였다. 나는 정말 오랫동안 슬라이드를 만들어본 적이 없기 때문이다. 그래서 여러 플랫폼을 찾아 다녔다. md 파일을 바로 슬라이드로 만들어주는 플랫폼 여러곳이 있었지만 미리캠버스가 가장 원하는 형태로 잘 만들어 주었다. pdf가 필요하긴 했지만 md를 pdf로 바꾸는 건 쉽기 때문에 괜찮았다. 슬라이드로 만드니 대략 나오는 장수는 35장 많이 줄이는 것이 필요 했다. 정말 핵심적인 슬라이드 한장을 고르고 그걸 위주로 내용을 재편집 했다. 그 한 장이 '오픈 소스 코드 읽기로 얻는 것들'이었다. 나도 이력서에 한 줄 넣기 혹은 회사 일 하다가 넣은 것이지만 이것보다는 직접 소스코드를 분석하고 오픈소스를 어떻게 운영하는지에 대해 많이 배웠기 때문이다. 발표 연습 가깝게는 아는 지인들을 총동원 했다. (글쓰기 모임, 아는 오픈 톡방, 회사) 이중에 회사는 사내 발표로 까지 이어져 용돈까지 벌었다. 매우 뜻하지 않게 금전적 이득이 있어 기분이 들떴다. 이때 대략 15분 정도의 분량으로 준비를 해갔다. 남은 5분은 사전리허설의 피드백을 받아 줄여볼 생각이었기 때문이었다. 반응이 좋았다. 내용이 알차다고 피드백을 들었고 전부터 우려했던 목소리 톤이나 속도도 괜찮다는 피드백을 받았다. 하지만 피드백 중에 성향이 갈리는 듯 하였다. 누군가는 \"그래서 오픈 소스 어떻게 기여할 수 있는건대?\" 또 누군가는 \"오픈 소스를 기여 해야하는 이유를 알 수 있어 좋았어요!\" 라고 했기 때문이다. 둘다 공감 되는 내용이었고 어느정도 상충이 되는 내용이었다. 상충이 되는 이유는 " - }, - { - "slug": "nodejs-contribution", - "title": "4시간 만에 Node.js PR 승인받기", - "date": "2025-08-10", - "excerpt": "4시간 만에 Node.js PR 승인받기 AI 페어 프로그래밍으로 오픈소스 진입 장벽 낮추기 “무조건 Node.js에 내 코드를 넣고 말겠다!” 오픈소스 기여가 점점 재미있어지고, 자신감도 차오르던 시기였다. 하지만 매일같이 이슈를 살펴봐도 여전히 모르는 부분이 많았다. C++ 코드가 ...", - "tags": [], - "series": "open-source", - "contentPreview": "4시간 만에 Node.js PR 승인받기 AI 페어 프로그래밍으로 오픈소스 진입 장벽 낮추기 “무조건 Node.js에 내 코드를 넣고 말겠다!” 오픈소스 기여가 점점 재미있어지고, 자신감도 차오르던 시기였다. 하지만 매일같이 이슈를 살펴봐도 여전히 모르는 부분이 많았다. C++ 코드가 보이기도 했고, fs 같은 코어 모듈이 대부분이었기 때문이다. (게다가 이슈를 완벽히 이해한 것도 아니었다.) 그러던 중 AI를 활용한 오픈소스 기여 모임을 알게 되었고, 거기서 본 한 링크가 나에게 혁신을 가져다주었다. --- 1. 이슈 찾기: AI로 시작하는 빠른 탐색 이슈 분석에 어려움을 느끼던 내게 구세주가 나타났다. 바로 이슈 수집기였다. 곧장 nodejs/node 저장소와 내 토큰을 입력하고 모든 이슈를 긁어왔다. (지금도 매일 한다.) 그중 눈에 들어온 이슈가 있었다. Issue 23: util.inspect incorrectly formats negative fractional numbers - 라벨: 없음 - 내용: numericSeparator: true 옵션 사용 시 음수 소수점 숫자 포맷팅 버그 - 원인: formatNumber 함수에서 -0 처리 시 부호 손실 - 해결 방향: 없음 - 적합도: 상 (재현 코드와 명확한 문제 설명) - 기술 난이도: 중 C++도 없고, 복잡한 코어 모듈도 아닌, 숫자 유틸 함수 하나를 수정하는 일이었다. 게다가 이슈가 올라온 지 5시간밖에 되지 않아 바로 댓글을 달고 선점했다. 곧 메인테이너가 해결 방향과 최적화 아이디어를 제시해주었고, 나는 지체 없이 코드를 수정하러 들어갔다. --- AI 활용 팁: 이슈 선택 시 체크리스트 - 난이도: 너무 어려운 영역(C++, 네이티브 모듈 등)은 피하고, 변경 범위가 명확한 이슈를 선택합니다. - 재현 가능성: 이슈 설명에 재현 코드나 명확한 조건이 포함되어 있는지 확인합니다. - 라벨 여부: 'good first issue', 'help wanted' 라벨은 초심자에게 좋은 출발점입니다. --- 2. 문제 분석: 버그 원인 파악하기 문제는 간단했다. util.inspect에서 numericSeparator 옵션을 켜면, 0과 1 사이의 음수 값에서 부호가 사라지는 현상이 있었다. 문제의 원인은 lib/internal/util/inspect.js에서 숫자를 문자열로 변환할 때, -0이 \"0\"으로 변환되어 부호가 사라지는 것이었다. --- 3. 개발 환경 구축: 로컬에서 Node.js 빌드하기 Node.js 저장소를 포크 후 클론 받아 AI CLI 환경에서 코드베이스를 학습시켰다. 처음에는 C++이 없어서 빌드 에러가 발생했다. AI와 함께 원인을 찾아보니 Command Line Tools 설치가 필요했다. 설치 후 다시 빌드하니 약 30분 만에 성공. 처음 직접 빌드한 Node.js를 실행했을 때, 테스트 코드가 정상 동작하는 것을 보고 꽤 뿌듯했다. --- AI 활용 팁: 빌드 에러 대처 - 환경 의존성: C++ 컴파일러, Python 버전 등 필수 의존성을 " - }, - { - "slug": "nextjs-contributor", - "title": "Next.js 오픈소스 기여: 2번 실패 후 성공 후기", - "date": "2025-08-05", - "excerpt": "Next.js 오픈소스 기여: 2번 실패 후 성공 후기 들어가며 \"띠링\" 새벽 2시, 내 핸드폰에 또 다른 GitHub 알림이 울렸다. 발신자: vercel/next.js [[제목] : Re:[vercel/next.js] Fix remote pattern (80294) (PR 80428...", - "tags": [], - "series": "open-source", - "contentPreview": "Next.js 오픈소스 기여: 2번 실패 후 성공 후기 들어가며 \"띠링\" 새벽 2시, 내 핸드폰에 또 다른 GitHub 알림이 울렸다. 발신자: vercel/next.js [[제목] : Re:[vercel/next.js] Fix remote pattern (80294) (PR 80428)](https://github.com/vercel/next.js/pull/80428) 아, 이건 하면 안 되는 거였구나... 빨간색 \"Closed\" 라벨이 붙은 내 PR을 멍하니 바라보며, 가슴이 철렁 내려앉았다. 잠은 이미 다 깼고, 구글링으로 찾은 \"How to contribute to Next.js\" 글들은 아무런 도움이 되지 않았다. 마치 미로에 갇힌 기분이었다. \"생각보다 많이 어렵네...\" 내적으로 혼잣말을 중얼거렸다. 이게 나의 두 번째 실패였다. 하지만 포기하고 싶지 않았다. 어딘가에서 '너도 할 수 있어'라는 목소리가 들리는 것 같았다. 한 달 후, 나는 Next.js Contributors 목록에 이름을 올렸다. 그 순간의 짜릿함과 벅참은 지금도 잊을 수 없다. 여러분도 오픈소스 기여에 도전하다가 좌절한 경험이 있으신가요? 실패가 두려워서 시도조차 못하고 계신가요? 그 과정에서 느꼈던 막막함과 불안감, 그리고 다시 일어서고 싶은 마음... 모두 이해합니다. 그 사이에 무슨 일이 있었는지, 지금부터 솔직하게 털어놓겠습니다. 첫 번째 실패: \"이런 게 개발자의 현실인가?\" Fix segment prefetches fail with HTTP 400 3개월 전, Next.js 이슈 페이지를 뒤적이던 나는 마치 보물을 발견한 듯 가슴이 뛰었다. \"이거다! 예제 코드도 있고, 문제 코드 추정 부분까지 친절하게 써있어. 이 정도면 금방 할 수 있겠지?\" 당시 내 마음은 설렘이 90%, 불안감이 10% 정도였다. 솔직히 말하면 \"이거 성공하면 이력서에 써도 되겠는걸?\" 이런 생각까지 들었다. 오픈소스 기여가 Next.js라니, 생각만 해도 가슴이 뛰었다. 실제로는 아무것도 모르는 상태로 무작정 도전했다. 지금 생각해보니 정말 용감했다. App Router의 prefetch라는 실험적인 기능에 덤벼들었는데, 이게 얼마나 복잡한 기능인지도 모르고 말이다. 로컬 환경 설정부터 막혀서 3일 동안 삽질했지만, 그래도 테스트 코드 구조만큼은 이해할 수 있었다. nextTestSetup()이라는 특별한 함수를 사용한다는 것도 이때 처음 알았다. 하지만 진짜 문제는 그 다음이었다. 테스트는 돌릴 수 있게 되었지만, 정작 실제 이슈를 어떻게 해결해야 할지 전혀 감이 오지 않았다. 코드베이스가 너무 복잡했고, 어디서부터 손을 대야 할지 막막했다. 결국 PR을 올리지도 못하고 포기했다. 그 순간의 감정: 허탈함과 함께 \"내가 너무 어려운 걸 골랐구나\"라는 뼈아픈 깨달음이었다. 💡 Next.js 테스트 환경 제대로 구축하기 일반적인 React 테스트와 달리 Next.js는 프레임워크 차원의 특수한 구조를 가지고 있다. 이를 모르면 며칠을 헤맬 수 있다. 왜 Next.js" - }, - { - "slug": "react-component-context-api-dropzone", - "title": "Context API를 활용한 DropZone 구현하기", - "date": "2025-07-30", - "excerpt": "[React Component] Context API를 활용한 DropZone 구현하기 평소처럼 Mantine의 Dropzone을 사용하고 있었는데, 문득 내부 구현이 궁금해졌습니다. 어떻게 이렇게 깔끔한 API를 제공할 수 있을까? tsx // Mantine Dropzone 사용 중....", - "tags": [], - "series": "react/component", - "contentPreview": "[React Component] Context API를 활용한 DropZone 구현하기 평소처럼 Mantine의 Dropzone을 사용하고 있었는데, 문득 내부 구현이 궁금해졌습니다. 어떻게 이렇게 깔끔한 API를 제공할 수 있을까? 마침 그때 디자인 팀에서 연락이 왔습니다. [디자이너]: \"파일 업로드 컴포넌트를 우리 디자인 시스템에 맞게 다시 만들어야 할 것 같아요. Mantine 스타일이 브랜드와 안 맞아서...\" [나]: \"아, 그럼 Dropzone도 자체 구현해야 하는 건가요?\" [디자이너]: \"네, 그리고 상태별로 다른 애니메이션이랑 아이콘도 써야 하고... 기본, 허용, 거부, 로딩 상태 모두 다르게 보여주세요!\" 순간 두 가지 생각이 스쳐갔습니다. \"어차피 다시 만들어야 한다면, Mantine의 내부 구현을 분석해서 더 나은 방식으로 만들어보자!\" 그렇게 Mantine의 Dropzone 컴포넌트를 뜯어보다가 Context API + 컴파운드 컴포넌트 패턴의 놀라운 조합을 발견했습니다. 1부: Mantine 분석과 자체 구현의 필요성 Mantine Dropzone 분석하기 먼저 Mantine의 Dropzone이 어떻게 동작하는지 살펴봤습니다. 정말 간단한 API로 복잡한 상태 관리를 숨기고 있더군요. [나]: \"어떻게 이렇게 간단한 API로 복잡한 상태 관리를 할 수 있지?\" 자체 구현 시 고려사항 디자인 시스템에 맞게 자체 구현하면서도 Mantine의 좋은 패턴은 그대로 가져가고 싶었습니다. 하지만 처음엔 단순하게 접근했죠. 2부: Context API를 활용한 컴파운드 컴포넌트 설계 컴파운드 컴포넌트 패턴이란? 컴파운드 컴포넌트 패턴은 여러 컴포넌트가 협력해서 하나의 기능을 구현하는 패턴입니다. HTML의 와 의 관계와 비슷해요. Context API를 통한 상태 공유 핵심 아이디어는 Context API로 DropZone의 모든 상태를 중앙 관리하고, 컴파운드 컴포넌트들이 이 상태를 구독하는 것입니다. 메인 DropZone 컴포넌트 구현 각 상태별 컴포넌트 구현 Idle 상태 컴포넌트 Accept 상태 컴포넌트 Reject 상태 컴포넌트 Loading 상태 컴포넌트 Context API + 컴파운드 컴포넌트의 핵심 패턴 여기서 가장 중요한 패턴은 각 컴포넌트가 Context를 구독해서 자신이 렌더링될 조건을 스스로 판단한다는 것입니다. 이 패턴의 혁신적인 점 1️⃣ 중앙 집중식 상태, 분산형 렌더링 2️⃣ 선언적 API로 의도 명확화 이런 방식의 핵심 장점: 1. 상태 추가 용이성: 새 상태 컴포넌트만 추가하면 됨 2. 독립적 테스트: 각 상태별 컴포넌트를 독립적으로 테스트 3. 코드 분할: 각 상태의 로직이 완전히 분리됨 4. 타입 안전성: 각 상태별로 다른 props 타입 적용 가능 5. 재사용성: 특정 상태만 필요한 곳에서 선택적 사용 3부: Panda CSS와 타입 안전성 Panda CSS를 활용한 스타일 시스템 타입 안전성 보장 실제 사용법 Context 기반 고급 활용 실무에서의 Context API 활용의 " - }, - { - "slug": "react-component-type-guard-button", - "title": "Type Guard를 활용한 여러가지 Button 구현하기", - "date": "2025-06-30", - "excerpt": "[React Component] Type Guard를 활용한 여러가지 Button 구현하기 드디어 디자인 시스템 프로젝트가 시작되었습니다! 팀에서 가장 먼저 구현하기로 한 컴포넌트는 Button입니다. 디자인 시스템에서 Button은 특별합니다. 가장 많이 사용되고, 가장 다양한 형태를...", - "tags": [], - "series": "react/component", - "contentPreview": "[React Component] Type Guard를 활용한 여러가지 Button 구현하기 드디어 디자인 시스템 프로젝트가 시작되었습니다! 팀에서 가장 먼저 구현하기로 한 컴포넌트는 Button입니다. 디자인 시스템에서 Button은 특별합니다. 가장 많이 사용되고, 가장 다양한 형태를 가지며, 다른 모든 컴포넌트의 기초가 되는 컴포넌트거든요. 설렘을 안고 피그마를 열어보았습니다. [나]: \"자, 어떤 버튼들이 있나 보자...\" 피그마를 살펴보니 생각보다 복잡합니다: - Solid Button: primary, secondary, assistive, white (4가지) - Outlined Button: primary, secondary, white (3가지) - Text Button: primary (1가지) [나]: \"어? 각 스타일마다 지원하는 variant가 다르네?\" 자세히 보니 더 복잡합니다: - assistive는 접근성을 위한 색상이라 solid에만 있음 - text 버튼은 보조적 역할이라 primary만 제공 - 각 스타일마다 다른 interaction 효과 적용 [나]: \"이거... 어떻게 구현하지? 🤔\" 순간 머릿속에서 이런 생각이 스쳐갑니다. \"단순하게 하나의 Button 컴포넌트로 만들면 될 줄 알았는데, 타입 안정성은 어떻게 확보하지?\" 1부: 문제 상황과 요구사항 분석 🎯 처음 생각한 단순한 접근 처음엔 간단할 것 같았습니다. 하나의 Button 컴포넌트에 모든 스타일을 때려넣으면 되겠다고 생각했거든요. 🚨 문제점 발견 피그마를 분석하고 실제로 구현하려고 하니까 문제가 보였습니다. [나]: \"잠깐, 이거 어떻게 구현하지? outlined 버튼에 assistive variant는 없는데 이걸 어떻게 타입으로 표현할까?\" [동료]: \"그냥 모든 variant를 다 허용하고 런타임에 체크하면 안 돼?\" [나]: \"그럼 컴파일 타임에 에러를 잡을 수 없잖아. 개발자가 실수로 text 버튼에 secondary variant 넣어도 TypeScript가 막지 못해.\" 이때 깨달은 문제점들 1. 타입 구분 불가: solid / outlined / text 버튼을 어떻게 구분할지 애매함 2. 디자인 규칙 위반 가능: text 버튼에 secondary, variant 같은 잘못된 조합 허용 3. TypeScript가 도움 안 됨: 무의미한 조합을 컴파일 타임에 잡아내지 못함 4. 코드 복잡성: 모든 조합을 if문으로 처리하면 가독성이 떨어짐 5. 확장성 부족: 새로운 버튼 스타일 추가할 때마다 기존 코드 수정 필요 [동료]: \"이런 식으로 하면 나중에 디자이너가 의도하지 않은 조합으로 버튼을 만들 수도 있겠네...\" [나]: \"맞아, 디자인 시스템의 의미가 없어지겠어. 어떻게 해야 할까?\" [시니어]: \"Union Type이랑 Type Guard 써봐. 깔끔하게 해결돼.\" 2부: Union Type과 Discriminated Union 활용 🎨 Discriminated Union 패턴 TypeScript의 Discrim" - }, - { - "slug": "react-component-toast", - "title": "15줄에서 2줄로: useSyncExternalStore 기반 React Toast 시스템 설계법", - "date": "2025-06-30", - "excerpt": "들어가며 안녕하세요, 여러분! 프론트엔드 개발자라면 누구나 한 번쯤 만들어보는 토스트 UI. 간단해 보이지만, 막상 구현하다 보면 \"이걸 어떻게 앱 어디서든 쉽게 호출하지?\", \"종류별로 다른 스타일은 어떻게 관리하지?\" 같은 고민에 빠지게 됩니다. 최근 mantine의 토스트 컴포넌트...", - "tags": [], - "series": "react/component", - "contentPreview": "들어가며 안녕하세요, 여러분! 프론트엔드 개발자라면 누구나 한 번쯤 만들어보는 토스트 UI. 간단해 보이지만, 막상 구현하다 보면 \"이걸 어떻게 앱 어디서든 쉽게 호출하지?\", \"종류별로 다른 스타일은 어떻게 관리하지?\" 같은 고민에 빠지게 됩니다. 최근 mantine의 토스트 컴포넌트를 분석할 기회가 있었습니다. 이 코드는 단순히 기능을 구현하는 것을 넘어, 유지보수성, 재사용성, 확장성까지 모두 잡는 훌륭한 아키텍처를 보여주었습니다. 우리의 리액트 컴포넌트를 한 단계 업그레이드할 수 있는 인사이트를 공유하고자 합니다. 대부분의 React 개발자들이 Toast 컴포넌트를 만들 때 다음과 같은 코드를 작성합니다. 하지만 이런 방식에는 몇 가지 문제가 있습니다. - 컴포넌트마다 반복되는 상태 관리 코드 - 여러 곳에서 Toast를 띄우려면 Context나 상태 끌어올리기 필요 - 비즈니스 로직(타이머, 큐 관리)과 UI 로직의 혼재 오늘은 이 모든 문제를 해결하는 혁신적인 Toast 시스템 설계를 소개하겠습니다. 목표 코드 장점 - Zero State: 컴포넌트에서 상태 관리 코드 없음 → 기존 방식: 매번 useState, useEffect로 상태 관리 (15줄 코드) → 새로운 방식: 상태 관리 코드 완전 제거 (2줄 호출) - Global Access: 앱 어디서든 동일한 API → 컴포넌트 계층 구조와 무관하게 어느 깊이에서든 접근 가능 → Props drilling이나 Context Provider 설정 불필요 - Type Safe: 컴파일 타임 오류 방지 → 잘못된 타입 전달 시 IDE에서 즉시 오류 표시 - Auto Management: 타이머, 큐, 애니메이션 자동 처리 → 자동 타이머: 3초 후 자동 닫힘, 수동 clearTimeout 불필요 → 큐 관리: 동시에 여러 토스트 표시 시 위치별 개수 제한 → 애니메이션: 등장/사라짐 효과 자동 처리, 상태 충돌 방지 핵심 아이디어 useSyncExternalStore의 힘 React 18에서 도입된 useSyncExternalStore는 React 외부의 상태를 안전하게 구독할 수 있게 해줍니다. 이를 활용하면: 왜 이 방식이 혁신적인가? 1. 동시성 안전성: React 18의 Concurrent Features와 완벽 호환 2. 독립적 상태: React 컴포넌트 생명주기와 무관하게 동작 3. 전역 접근성: 컴포넌트 트리 어디서든 접근 가능 4. 최적화: 필요한 컴포넌트만 리렌더링 3-Layer 아키텍처 각 레이어는 명확한 책임을 가지며, 서로 독립적으로 테스트하고 수정할 수 있습니다. 단계별 구현 1단계: Store 엔진 구현 범용 상태 관리 시스템 구축 핵심 특징 - 타입 안전성: 제네릭으로 완벽한 타입 추론 - 메모리 효율성: WeakMap이 아닌 Set 사용으로 명시적 구독 해제 - 동시성 지원: useSyncExternalStore로 React 18 Concurrent Features 호환 2단계: Toast 비즈니스 로직 타입 시스템 설계 비즈니스 로직 구현 핵심 " - }, - { - "slug": "2025-mid-year-review", - "title": "개발자에서 기여자로: 기술 블로그와 오픈소스가 바꾼 나의 2025년 상반기", - "date": "2025-06-17", - "excerpt": "들어가며 2025년 상반기를 돌아보니, 가장 크게 변화한 것은 \"나만 알고 있던 지식을 세상과 나누기 시작 했다\"는 점이다. 그동안 개발자로서 쌓아온 경험들과 고민을 글로 정리하고, 오픈소스에 기여 하면서 진정한 의미의 성장을 경험한 상반기였다. --- 🌟 기술 블로그: 지식 공유의 ...", - "tags": [], - "series": "회고/2025", - "contentPreview": "들어가며 2025년 상반기를 돌아보니, 가장 크게 변화한 것은 \"나만 알고 있던 지식을 세상과 나누기 시작 했다\"는 점이다. 그동안 개발자로서 쌓아온 경험들과 고민을 글로 정리하고, 오픈소스에 기여 하면서 진정한 의미의 성장을 경험한 상반기였다. --- 🌟 기술 블로그: 지식 공유의 시작 2024년 12월 23일, 한 해를 마무리하며 회고글을 작성했다. 평소 활발히 소통하던 개발자 커뮤니티에 공유했을 때, 예상치 못한 피드백을 받았다. \"평소 기술 관련 답변을 잘 해주시는데, 회고에는 기술적인 내용이 하나도 없네요.\" 이 한마디가 내게 새로운 방향을 제시했다. 그 자리에서 바로 결심했다. \"그래, 기술 블로그로 내 경험과 지식을 글로 남겨보자!\" 첫 글의 용기와 성공적인 반응 회고글을 바탕으로 작성할 주제를 뽑아보니 대략 14개 정도 나왔다. 한 달에 12개씩 작성하면 일 년을 채울 수 있겠다고 생각했다. 첫 글로는 내가 많이 고민했고 프로젝트에 성공적으로 적용한 아키텍처 도입 이야기를 선택했다. 내용에 대한 고민도 있었지만, 가장 큰 고민은 \"내가 이런 글을 쓰고 공유해도 될까?\" 였다. 하지만 완성 후 커뮤니티에 공유한 결과는 예상을 뛰어넘었다. 발간 후 일주일 만에 500회 조회수를 기록했고, 현재는 1,500회를 돌파했다. 첫 글의 좋은 반응 덕분에 '나라는 개발자가 이런 생각으로 개발한다'는 것을 알릴 수 있어 뿌듯했고, 자신감을 얻어 계속 글을 쓰게 되었다. 글쓰기 모임과 발표 경험 더 나은 글을 쓰고 싶어 글쓰기 모임에도 가입했다. 내 글에 대한 리뷰를 받고 싶은 마음도 있었고, 모임이 발표로 마무리되는 것도 매우 마음에 들었다. 실제로 Panda CSS 사용기를 주제로 발표했는데, 질의응답 시간에서 놀라운 경험을 했다. \"Panda CSS에서 조건문 사용이 힘들다고 하셨는데, 그럼 그걸 사용해야 할 때 어떻게 해야 하나요?\" \"다른 디자인 시스템에는 어떻게 자연스럽게 적용이 가능한가요?\" 10건 이상의 질문과 답변을 주고받으며 사람들이 무엇을 궁금해하는지, 요즘 트렌드는 어떤 것인지 알게 되었다. 정말 소중한 경험이었다. 질문에서 시작된 시리즈 글 또 다른 의미 있는 경험은 누군가의 질문을 글로 작성한 것이다. \"에러 바운더리에서는 비동기 에러를 못 잡지 않나요?\" 이 한마디에 바로 JavaScript 에러 핸들링에 대한 시리즈를 작성했다. JavaScript → React → Next.js 순서로 작성하고 테스트 코드까지 작성해 올렸다. 이제는 누군가 비슷한 질문을 하면 이 시리즈 링크를 공유하고 있다. 지속적인 성장과 새로운 시리즈 14개의 주제를 4월 3일까지 다 작성해버린 후, 새로운 주제를 찾기 시작했다. 마침 첫 번째 오픈소스 기여를 하게 되어, 기여의 기쁨과 함께 새로운 글 주제를 찾은 것에 더욱 기뻤다. 최근에는 첫 글로 썼던 아키텍처 이야기를 더 이해하기 쉽게 하기 위해 [[Typescript로 설계하는 프로젝트]](https://velog.io/@rewq5991/series/typescript-proje" - }, - { - "slug": "typescript-project-domain-design", - "title": "[Typescript로 설계하는 프로젝트] \"같은 로직 또 복사했어요?\" Domain 모델로 책임 분리하기", - "date": "2025-06-15", - "excerpt": "들어가며 오후 4시, 또 다시 울리는 슬랙 알림... [기획자]: \"저번에 만든 사용자 상태 로직 잘 쓰고 있어요! 그런데 이번엔 사용자가 특정 액션을 할 수 있는지 검증하는 로직도 추가해 주세요.\" [나]: \"네, 어떤 검증 로직인가요?\" [기획자]: \"사용자가 글을 작성할 수 있는지...", - "tags": [], - "series": "[Typescript로 설계하는 프로젝트]", - "contentPreview": "들어가며 오후 4시, 또 다시 울리는 슬랙 알림... [기획자]: \"저번에 만든 사용자 상태 로직 잘 쓰고 있어요! 그런데 이번엔 사용자가 특정 액션을 할 수 있는지 검증하는 로직도 추가해 주세요.\" [나]: \"네, 어떤 검증 로직인가요?\" [기획자]: \"사용자가 글을 작성할 수 있는지, 댓글을 달 수 있는지, 파일을 업로드할 수 있는지... 뭐 이런 권한들이요. 그리고 각각 다른 조건들이 있어요!\" [나]: (음... 이것도 Service에서 함수로 만들면 되겠지만, 사용자와 관련된 로직들이 점점 많아지고 있네. 그리고 검증 로직이라면 사용자 자체가 판단할 수 있는 로직 같은데...) [동료]: \"사용자 관련 로직이 Service에 너무 많아지는 것 같은데, 사용자 자체가 가져야 할 책임과 Service가 가져야 할 책임을 나눠보는 게 어떨까요?\" 이런 상황, 어떻게 해결하시겠어요? 지난 글에서는 Service Layer를 통해 비즈니스 로직을 분리하고 재사용 가능한 구조를 만드는 방법을 다뤘습니다. 하지만 실제 프로젝트에서는 이런 상황을 만나게 됩니다. - Service 파일이 수백 줄로 비대해짐 - 사용자 관련 함수들이 여기저기 흩어져 있음 - 새로운 사용자 기능 추가할 때마다 어디에 코드를 넣어야 할지 고민됨 - \"사용자가 할 수 있는 것\"에 대한 로직이 한 곳에 모여있지 않음 이번글에선 이런 문제를 해결하기 위해 Type으로 시작해서 점진적으로 도메일 모델로 발전시키는 방법과, 함수형 접근 방식과 객체지향 접근 방식의 선택 기준에 대해 알아보겠습니다. --- 현재 상황: 타입 기반 설계의 한계 💡 핵심 요약 - 문제점: Service에 모든 로직 집중 → 파일 비대화, 응집도 부족, 확장성 제한 - 근본 원인: 타입과 로직이 분리되어 도메인 로직이 분산됨 - 해결 방향: 점진적으로 도메인 모델을 도입하여 관련 로직을 응집 지금까지 우리가 사용한 방식 이 방식의 문제점 1. Service 비대화 - 사용자와 관련된 모든 로직이 Service에 집중되어 파일이 거대해집니다. 2. 응집도 부족 - 사용자의 속성과 그 속성을 다루는 로직이 분리되어 있어 관련성을 파악하기 어렵습니다. 3. 확장성 제한 - 새로운 사용자 관련 기능이 추가될 때마다 Service 파일을 수정해야 합니다. 4. 도메인 지식 분산 - \"사용자가 할 수 있는 것\"에 대한 도메인 지식이 여러 곳에 흩어져 있습니다. --- 지금까지의 여정: 타입 중심 설계에서 도메인 모델로 [나]: 잠깐, 도메인 모델 얘기하기 전에 한 가지 짚고 넘어가야 할 게 있어요. [독자]: 뭔가요? [나]: 지금까지 우리가 HTTP API 설계, Service Layer 설계를 하면서 계속 @/shared에서 타입을 import 해왔잖아요? [독자]: 맞아요! HTTP 설계 글에서 이런 코드 봤죠. [나]: 정확히 그거예요! 그리고 그때 \"도메인 모델 재사용\"이라는 용어도 나왔고요. [독자]: 그런데 그게 왜 중요한건지 깊이 생각해본 적은 없었어요. [나]: 바로 그거예요! 이제 그 이유" - }, - { - "slug": "typescript-project-service-design", - "title": "[Typescript로 설계하는 프로젝트] \"원래 있던 기능이니 금방 하시죠?\" 당하지 않는 Service Layer 설계 전략", - "date": "2025-06-08", - "excerpt": "들어가며 겨우 백엔드의 요청을 쳐내고 다시 피곤함에전 모습으로 테스크를 마무리하려는 순간 이번엔 제 슬랙이 울립니다. [기획자]: \"급하게 기획이 바뀌어서요. 이거 프론트에서 추가로 수정해 주셔야 할 것 같아요. 아직 마무리 다 안 하신 거 맞죠?\" [나]: \"네 아직 마무리 안 했어요...", - "tags": [], - "series": "[Typescript로 설계하는 프로젝트]", - "contentPreview": "들어가며 겨우 백엔드의 요청을 쳐내고 다시 피곤함에전 모습으로 테스크를 마무리하려는 순간 이번엔 제 슬랙이 울립니다. [기획자]: \"급하게 기획이 바뀌어서요. 이거 프론트에서 추가로 수정해 주셔야 할 것 같아요. 아직 마무리 다 안 하신 거 맞죠?\" [나]: \"네 아직 마무리 안 했어요. 수정 사항이 뭔가요?\" [기획자]: \"별거 없어요! 다른 쪽에 만든 기능이긴 한대 대신에 사용자의 데이터가 특정 조건에 따라 카드의 색깔이 바뀌어야 합니다. 원래 있던 기능이니 금방 하시죠?\" [나]: (그거 거기에만 쓴다며... 그래서 그쪽 로직하고 딱 붙여 놓은건대... ) \"네 하지만 시간은 좀 걸릴 것 같아요 PM 하고 이야기는 하고 오신 거죠?\" 어떻게 하면 이런 로직을 재활용하기 쉽게 만들 수 없을까? 지난번 API도 구조적으로 설계 했는대 이것도 그렇게 할 수 있지 않을까? 이전글에서는 Type-Safe Http class을 설계하고 Type을 구조적으로 설계하는 것에 대해 이야기 했습니다. 이번글에서는 프론트에서 쓰이는 비즈니스 로직을 분리하는 부분에 관하여 이야기해 볼까 합니다. 여러분이 여기까지 따라오셨다면 이미 http와 Api 호출부를 나누어 놓았을 것입니다. 🎉 축하합니다! Layer를 나누신거고 그럼 그 이후에 로직을 붙여 나가는건 별로 어렵지 않습니다. 대신에 이번 Layer를 저는 Service Layer라고 부르고 이 Layer가 가지는 장점에 대해서 설명드리겠습니다. 🔨 기존 Api + Business logic의 문제점 보통 이렇게 바로 api 로직과 비즈니스 로직이 ui에 한 곳에 작성되어 있거나 커스텀 훅에 같이 작성되어 있습니다. 이러한 접근 방식은 다음과 같은 심각한 문제를 초래합니다! 1. 재사용이 어려워짐: 비즈니스 로직이 컴포넌트에 직접 구현되면, 동일한 로직을 다른 컴포넌트에서 사용하려면 코드를 복사-붙여넣기 해야 합니다. 2. 테스트 작성이 어려움: UI 컴포넌트와 비즈니스 로직이 결합되어 있으면, 비즈니스 로직만 독립적으로 테스트하기 어렵습니다. 3. 관심사 분리가 되지 않아 유지보수가 힘듦: UI 표현과 비즈니스 로직은 서로 다른 관심사입니다. 이들이 혼합되면 코드의 가독성이 떨어집니다. 🛠️ 비즈니스 로직을 서비스 함수로 분리 이제 이런 문제들을 해결하기 위해 Service Layer를 설계 방법을 알아보겠습니다. 1. 관심사 분리/재사용성 증가 1. 비즈니스 로직 - 비즈니스 로직에만 관심을 가집니다. 2. CSS - 스타일링에만 관심을 가집니다. 3. UI - 렌더링에만 관심을 가집니다. 2. 재사용성 확인: 다른 컴포넌트에서의 활용 이제 기획자가 \"다른 곳에서도 같은 로직을 써주세요\" 라고 했을 때, 정말 간단하게 해결할 수 있는지 확인해 보겠습니다. 코드 복사 없이 getUserStatus 함수만 import해서 즉시 사용 가능! 정말 \"별거 없게\" 되었습니다. 3. 테스트 코드 작성 용이성 비즈니스 로직이 분리되어 간단한 mock 객체 하나만으로도 독립적인 테스트 코드 작성이 가능합니" - }, - { - "slug": "typescript-project-service-di-design", - "title": "[Typescript로 설계하는 프로젝트] \"원래 있던 기능이니 금방 하시죠?\" 당하지 않는 Service Layer 설계 전략 With Di", - "date": "2025-06-08", - "excerpt": "들어가며 겨우 백엔드의 요청을 쳐내고 다시 피곤함에전 모습으로 테스크를 마무리하려는 순간 이번엔 제 슬랙이 울립니다. [기획자]: \"급하게 기획이 바뀌어서요. 이거 프론트에서 추가로 수정해 주셔야 할 것 같아요. 아직 마무리 다 안 하신 거 맞죠?\" [나]: \"네 아직 마무리 안 했어요...", - "tags": [], - "series": "[Typescript로 설계하는 프로젝트]", - "contentPreview": "들어가며 겨우 백엔드의 요청을 쳐내고 다시 피곤함에전 모습으로 테스크를 마무리하려는 순간 이번엔 제 슬랙이 울립니다. [기획자]: \"급하게 기획이 바뀌어서요. 이거 프론트에서 추가로 수정해 주셔야 할 것 같아요. 아직 마무리 다 안 하신 거 맞죠?\" [나]: \"네 아직 마무리 안 했어요. 수정 사항이 뭔가요?\" [기획자]: \"별거 없어요! 다른 쪽에 만든 기능이긴 한대 대신에 사용자의 데이터가 특정 조건에 따라 카드의 색깔이 바뀌어야 합니다. 원래 있던 기능이니 금방 하시죠?\" [나]: (그거 거기에만 쓴다며... 그래서 그쪽 로직하고 딱 붙여 놓은건대... ) \"네 하지만 시간은 좀 걸릴 것 같아요 PM 하고 이야기는 하고 오신 거죠?\" 어떻게 하면 이런 로직을 재활용하기 쉽게 만들 수 없을까? 지난번 API도 구조적으로 설계했는데 이것도 그렇게 할 수 있지 않을까? 이전글에서는 Type-Safe Http class을 설계하고 Type을 구조적으로 설계하는 것에 대해 이야기했습니다. 해당 글에서는 서버 API Type을 설계하고 제네릭을 활용한 HTTP 클래스를 통해 타입 안전성을 확보하는 방법을 다루었습니다. 특히 DI을 활용하여 HTTP 클라이언트를 추상화하고 테스트하기 쉬운 코드를 작성하는 방법을 설명했습니다. 의존성 주입(DI) 이란 무엇일까요? 간단히 말하면, 한 객체가 다른 객체를 직접 생성하거나 참조하는 대신, 외부에서 필요한 객체를 전달받는 디자인 패턴입니다. 이는 코드의 결합도를 낮추고 재사용성과 테스트 용이성을 높여줍니다. 예를 들어, HTTP 클라이언트가 필요한 서비스 클래스는 직접 HTTP 클라이언트를 생성하는 대신, 생성자나 메서드 인자로 전달받을 수 있습니다. 이번글에서는 프론트에서 쓰이는 비즈니스 로직을 분리하여 Service Layer를 구성하고, 의존성 주입을 통해 재사용 가능하고 테스트하기 쉬운 코드를 작성하는 방법에 대해 이야기해 볼까 합니다. 여러분이 여기까지 따라오셨다면 이미 http와 Api 호출부를 나누어 놓았을 것입니다. 🎉 축하합니다! 레이어를 나누신거고 그럼 그 이후에 로직을 붙여 나가는건 별로 어렵지 않습니다. 대신에 이번 레이어를 저는 Service Layer라고 부르고 이 Layer가 가지는 장점에 대해서 설명드리겠습니다. 🔨 기존 Api + Business logic의 문제점 보통 이렇게 바로 api 로직과 비즈니스 로직이 ui에 한 곳에 작성되어 있거나 커스텀 훅에 같이 작성되어 있습니다. 이러한 접근 방식은 다음과 같은 심각한 문제를 초래합니다! 1. 재사용이 어려워짐: 비즈니스 로직이 컴포넌트에 직접 구현되면, 동일한 로직을 다른 컴포넌트에서 사용하려면 코드를 복사-붙여넣기 해야 합니다. 2. 테스트 작성이 어려움: UI 컴포넌트와 비즈니스 로직이 결합되어 있으면, 비즈니스 로직만 독립적으로 테스트하기 어렵습니다. 3. 관심사 분리가 되지 않아 유지보수가 힘듦: UI 표현과 비즈니스 로직은 서로 다른 관심사입니다. 이들이 혼합되면 코드의 가독성이 떨어집니다. 🛠️ 비즈니스" - }, - { - "slug": "typescript-project-api-design", - "title": "[Typescript로 설계하는 프로젝트] Type 설계의 시작: 견고한 서버 API Type 설계하기", - "date": "2025-06-01", - "excerpt": "들어가며 피곤에 쩔은 모습으로 하나의 테스크를 마무리 하는 순간 백엔드 개발자가 다가옵니다. \"죄송하지만 이번에 만든 api 중에 하나의 리스폰스가 변동 될 것 같습니다.\" \"User로 정의한 스키마 중에 name이 빠질 것 같아요.\" 순간 머릿속에서 여기저기 대강 흩어져 있는 User...", - "tags": [], - "series": "[Typescript로 설계하는 프로젝트]", - "contentPreview": "들어가며 피곤에 쩔은 모습으로 하나의 테스크를 마무리 하는 순간 백엔드 개발자가 다가옵니다. \"죄송하지만 이번에 만든 api 중에 하나의 리스폰스가 변동 될 것 같습니다.\" \"User로 정의한 스키마 중에 name이 빠질 것 같아요.\" 순간 머릿속에서 여기저기 대강 흩어져 있는 User 비스무리한 것들이 떠오릅니다. \"API 호출 부터 확인해서 하나 하나 찾아야 하나... 내가 안 빼먹고 깔끔하게 다 찾아서 수정할 수 있을까? 얼마나 오래 걸릴까?\" 이런 생각들이 머릿속을 스쳐가면서 백엔드 개발자에게 이야기 합니다. \"Pm이랑 이야기 되신거죠?(일정 늘어나는거 이야기 하고 온거죠?)\" Type을 구조적으로 설계하면 이런 상황을 좀 더 쉽게 풀 수 있지 않을까? 이전 글에서는 Type-Driven-Development를 소개하면서 타입을 설계 도구로 활용하는 방법에 대해 이야기했습니다. 이번 글에서는 Type 설계의 첫 단계로, 서버 API Type을 설계하는 방법을 다루고자 합니다. 프론트엔드는 서버로부터 전달받은 데이터를 기반으로 사용자 인터페이스를 구성합니다. 현대적인 웹 애플리케이션은 대부분 클라이언트-서버 아키텍처로 구성되어 있어, 프론트엔드 개발자는 백엔드 API가 정의한 스키마를 그대로 수용해야 하는 경우가 많습니다. (만약 풀스택으로 혼자 개발한다면, 백엔드의 엔티티나 DTO를 프론트엔드 타입으로 바로 활용할 수도 있습니다.) 이러한 구조에서 서버 API 스키마를 명확히 정의하는 것은 프론트엔드의 타입 시스템을 설계하는 것과 같습니다. 백엔드에서 정의한 API 응답의 구조, 데이터 타입, 필드 제약 조건 등이 프론트엔드의 타입 정의로 직접 연결되기 때문입니다. 서버의 API 스키마는 프론트엔드 타입 시스템의 기반이 되어, 클라이언트와 서버 간의 데이터 일관성과 타입 안정성을 보장합니다. 프론트엔드에서는 이렇게 정의된 서버 API 스키마를 바탕으로 타입을 정의하고, 추상화된 HTTP 클라이언트 클래스를 활용합니다. 이를 통해 API 호출 시 타입 안정성을 확보할 수 있을 뿐만 아니라, 컴파일 타임에 오류를 사전에 방지할 수 있습니다. 🔨 기존 HTTP 클라이언트의 문제점 많은 프로젝트에서 서버 통신을 위한 HTTP 클라이언트를 다음과 같이 사용합니다. 이러한 접근 방식은 다음과 같은 심각한 문제를 초래합니다! 1. 타입 안전성 부재: 응답 데이터에 대한 타입 검증이 없어 런타임 오류 위험이 높습니다. 2. 타입 중복과 불일치: 동일한 API에 대해 여러 개발자가 서로 다른 타입을 정의하여 혼란을 가중시킵니다. 3. 유지보수 비용 증가: API 변경 시 모든 호출 지점을 찾아 수정해야 하며, 누락된 곳이 있으면 런타임 오류로 이어집니다. 4. 테스트 어려움: 타입이 명확하지 않아 테스트 작성이 어렵고, mock 데이터 생성도 복잡해집니다. 💡 Type-Safe HTTP 클래스 설계 원칙 이제 이런 문제들을 해결하는 Type-Safe한 HTTP 클래스 설계 방법을 알아보겠습니다. 1. 제네릭을 활용한 요청/응답 타입 명시 HT" - }, - { - "slug": "typescript-project-api-di-design", - "title": "[Typescript로 설계하는 프로젝트] Type 설계의 시작: 견고한 서버 API Type 설계하기 With DI", - "date": "2025-06-01", - "excerpt": "들어가며 피곤에 쩔은 모습으로 하나의 테스크를 마무리 하는 순간 백엔드 개발자가 다가옵니다. \"죄송하지만 이번에 만든 api 중에 하나의 리스폰스가 변동 될 것 같습니다.\" \"User로 정의한 스키마 중에 name이 빠질 것 같아요.\" 순간 머릿속에서 여기저기 대강 흩어져 있는 User...", - "tags": [], - "series": "[Typescript로 설계하는 프로젝트]", - "contentPreview": "들어가며 피곤에 쩔은 모습으로 하나의 테스크를 마무리 하는 순간 백엔드 개발자가 다가옵니다. \"죄송하지만 이번에 만든 api 중에 하나의 리스폰스가 변동 될 것 같습니다.\" \"User로 정의한 스키마 중에 name이 빠질 것 같아요.\" 순간 머릿속에서 여기저기 대강 흩어져 있는 User 비스무리한 것들이 떠오릅니다. \"API 호출 부터 확인해서 하나 하나 찾아야 하나... 내가 안 빼먹고 깔끔하게 다 찾아서 수정할 수 있을까? 얼마나 오래 걸릴까?\" 이런 생각들이 머릿속을 스쳐가면서 백엔드 개발자에게 이야기 합니다. \"Pm이랑 이야기 되신거죠?(일정 늘어나는거 이야기 하고 온거죠?)\" Type을 구조적으로 설계하면 이런 상황을 좀 더 쉽게 풀 수 있지 않을까? 이전 글에서는 Type-Driven-Development를 소개하면서 타입을 설계 도구로 활용하는 방법에 대해 이야기했습니다. 이번 글에서는 Type 설계의 첫 단계로, 서버 API Type을 설계하는 방법을 다루고자 합니다. 프론트엔드는 서버로부터 전달받은 데이터를 기반으로 사용자 인터페이스를 구성합니다. 현대적인 웹 애플리케이션은 대부분 클라이언트-서버 아키텍처로 구성되어 있어, 프론트엔드 개발자는 백엔드 API가 정의한 스키마를 그대로 수용해야 하는 경우가 많습니다. (만일 프론트 혼자서 서비스를 구성한다고 하면 엔티티나 dto로 정의 한 것이 하나의 타입으로써 사용 할 수 있습니다.) 이러한 구조에서 서버 API 스키마를 명확히 정의하는 것은 프론트엔드의 타입 시스템을 설계하는 것과 같습니다. 백엔드에서 정의한 API 응답의 구조, 데이터 타입, 필드 제약 조건 등이 프론트엔드의 타입 정의로 직접 연결되기 때문입니다. 서버의 API 스키마는 프론트엔드 타입 시스템의 기반이 되어, 클라이언트와 서버 간의 데이터 일관성과 타입 안정성을 보장합니다. 프론트엔드에서는 이렇게 정의된 서버 API 스키마를 바탕으로 타입을 정의하고, HTTP 클라이언트를 추상화한 클래스를 활용합니다. 이를 통해 API 호출 시 타입 안정성을 확보할 수 있을 뿐만 아니라, 컴파일 타임에 오류를 사전에 방지할 수 있습니다. 🔨 기존 HTTP 클라이언트의 문제점 많은 프로젝트에서 서버 통신을 위한 HTTP 클라이언트를 다음과 같이 사용합니다. 이러한 접근 방식은 다음과 같은 심각한 문제를 초래합니다! 1. 타입 안전성 부재: 응답 데이터에 대한 타입 검증이 없어 런타임 오류 위험이 높습니다. 2. 타입 중복과 불일치: 동일한 API에 대해 여러 개발자가 서로 다른 타입을 정의하여 혼란을 가중시킵니다. 3. 유지보수 비용 증가: API 변경 시 모든 호출 지점을 찾아 수정해야 하며, 누락된 곳이 있으면 런타임 오류로 이어집니다. 4. 테스트 어려움: 타입이 명확하지 않아 테스트 작성이 어려우며, mock 데이터 생성이 불필요하게 되어 복잡해집니다. 💡 Type-Safe HTTP 클래스 설계 원칙 이제 이런 문제들을 해결하는 Type-Safe한 HTTP 클래스 설계 방법을 알아보겠습니다. 1. 제네릭을 활용" - }, - { - "slug": "typescript-project-design", - "title": "[Typescript로 설계하는 프로젝트] 당신의 Type, 어디까지 연결되어 있나요?", - "date": "2025-05-05", - "excerpt": "[타입으로 설계하는 프로젝트] 당신의 Type, 어디까지 연결되어 있나요? 들어가며 플래닝이 끝나고 난 뒤 저에게 주어진 테스크를 살펴 봅니다. \"뭐시기 뭐시기 기능 수정 및 삭제\" 큰 기능 아니니 그냥 지워도 될거라는 저의 생각은 조만간 큰 버그를 가져왔습니다. 테스트 서버에 올려보니...", - "tags": [], - "series": "[Typescript로 설계하는 프로젝트]", - "contentPreview": "[타입으로 설계하는 프로젝트] 당신의 Type, 어디까지 연결되어 있나요? 들어가며 플래닝이 끝나고 난 뒤 저에게 주어진 테스크를 살펴 봅니다. \"뭐시기 뭐시기 기능 수정 및 삭제\" 큰 기능 아니니 그냥 지워도 될거라는 저의 생각은 조만간 큰 버그를 가져왔습니다. 테스트 서버에 올려보니 직접 페이지를 가야만 터지는 수많은 에러들... undefined is not a function 그렇게 미울 수가 없었습니다. 타입스크립트가 null 일 수도 있다는대? 그냥 ! 찍어버리지뭐 하지만 테스트 서버에 올리니 터지는 수많은 에러들... undefined is not a function 그렇게 미울 수가 없었습니다. 이거 예전에 만든 타입 같은대 살짝 다르네 그냥 하나더 만들지뭐 (벌써 5개째 만드는 중) 타입스크립트를 사용 했는대 개발 시간만 늘어나고 디버깅 시간만 늘어나는지 어디 좋은 글들 보면 버그가 줄어든다는대 난 왜 버그 투성이에 유지보수 조차 더 힘들어지는 걸까? \"왜 타입스크립트로 개발했는데도 런타임 에러가 끊이지 않을까?\" 많은 시간을 들여 타입스크립트로 전환했지만, 여전히 undefined is not a function 에러에 시달리고 계신가요? 대규모 프로젝트에서 타입스크립트의 진정한 가치는 단순한 자동완성이 아닌, 견고한 타입 설계에서 비롯됩니다. 프로젝트를 처음 들어갔을 때, 저는 가장 먼저 확인하는 것 중 하나는 Type입니다. Type 설계를 보면 데이터의 흐름을 알 수 있고 애플리케이션의 설계에 대해서 이해를 할 수 있다는 기대감 입니다. 하지만 컴파일 오류를 만을 피하기 위한 @ts-ignore, @ts-expect-error, @ts-nocheck과 any, as ... 및 아래와 같은 코드를 보면 머리부터 지끈거리기 시작 합니다. - 서버 API의 타입은 호출하는 곳에서 그때그때 만들거나 as로 무시 - 라이브러리의 제네릭은 무시하고 any로 대체 - 도메인 타입이 중복 선언되고 일관성이 없음 - 타입이 기능별로 흩어져 있고, 연결성이 없음 이런 상태에서는 타입이 안정성을 주는 도구가 아닌, 추가적인 관리 부담으로 작용합니다. 개발자들은 점차 타입스크립트의 본질적 가치를 포기하고 \"자바스크립트 + 자동완성\" 수준으로 타협하게 됩니다. 🚨 분리된 타입의 실제 문제점 - 기술 부채 증가: 중복되고 불일치한 타입 정의가 코드베이스 전체에 퍼집니다. - 온보딩 어려움: 신규 개발자들은 일관성 없는 타입 패턴에 적응하느라 시간을 낭비합니다. - 디버깅 지옥: API 변경 시 타입 불일치로 인한 버그 추적이 기하급수적으로 어려워집니다. - 개발 속도 저하: 코드를 변경할 때마다 예상치 못한 타입 에러와 싸워야 합니다. 💪 타입 중심 설계의 장점 - 컴파일 타임 안정성: API 변경 시 영향 범위를 즉시 파악할 수 있습니다. - 자동 문서화: 타입 자체가 코드의 의도를 명확하게 전달합니다. - 개발 경험 향상: 자동완성과 타입 추론이 실제로 믿을 수 있게 됩니다. - 리팩토링 자신감: 광범위한 코드 변경도 타입 시스템의" - }, - { - "slug": "pnpm-eslint-not-working", - "title": "pnpm 10 업그레이드 후 ESLint 설정이 사라졌어요?! (feat. 호이스팅)", - "date": "2025-05-01", - "excerpt": "0. 프롤로그 pnpm 9 → 10 업그레이드 후 monorepo에서 eslint가 동작하지 않는 문제를 겪은 경험을 공유 합니다. --- 1. 상황설명 저희 회사는 pnpm을 패키지 매니저로 사용하고 있습니다. 최근 pnpm 9에서 pnpm 10으로 업그레이드를 진행했습니다. 업그레이...", - "tags": [], - "series": null, - "contentPreview": "0. 프롤로그 pnpm 9 → 10 업그레이드 후 monorepo에서 eslint가 동작하지 않는 문제를 겪은 경험을 공유 합니다. --- 1. 상황설명 저희 회사는 pnpm을 패키지 매니저로 사용하고 있습니다. 최근 pnpm 9에서 pnpm 10으로 업그레이드를 진행했습니다. 업그레이드 이후, 기존에 잘 동작하던 eslint가 더 이상 제대로 실행되지 않는 문제가 발생했습니다. 예시 프로젝트 구조 --- 2. 문제 원인 분석 9버전에서는 패키지를 최상단에 설치를 하면 같은 경로 nodemodules로 설치가 되었습니다. 그래서 각 앱과 패키지에서 로드 하는대에서 문제가 없었지만 10버전 부터는 최상단으로 올라오지 않고 그대로 패키지 않에 들어 있는 문제가 생겼습니다. 문제 생기기전 문제가 생긴 후 이렇게 로드가 되면 결국 @config 안에만 eslint가 설치가 되어 사용할수가 없게 되어버립니다. 2.1 이슈 탐색 pnpm issues를 찾아보니 관련 이슈가 올라왔다. pnpm/issues/8378 내용을 살펴보면 eslint의 9버전이 released가 되면서 eslint config가 flat로 바뀌어 더이상 모듈을 호이스트 안 하고 직접 찾아올 수 있게 된겁니다. 사이드 이펙트에대하서 논의가 있었지만 사라진 옵션을 직접 추가하면 된다는 댓글이 있었고 그대로 진행이 되었던겁니다. 2.2 해결 방안 1. 새롭게 eslint9로 설정하여 셋팅한다. - 현재 여유가 없고 기존에 사용하던 룰이 아직 flat에 지원을 안하는 것도 있어 아직은 시기상조 2. eslint를 root에 설치하지 말고 각 app에 설치한다. - husky에 설정해둔 스크립트가 루트 기준으로 동작을 하고 있어 추가 작업이 필요 3. 사라진 옵션을 직접 추가 한다. - 가장 간단하고 개발 관련 패키지여서 사이드이펙트도 없음 --- 3. 해결 기존에도 사용하고 옵션이었던 3번으로 해결 하였고, 추후에 eslint9 버전을 적용할 때에 해결 하는것으로 결정하였다. --- 4. 느낀점 이번 문제는 pnpm의 버전을 업그레이드 하면서 생긴 문제라는 점을 인식을 하고는 있었지만 브레이크포인트에도 없어 찾기가 어려웠다. 혹시나 해서 gemini에게 물어보니 해당 링크를 찾아주었다. 여러모로 내 시간을 아껴준 것 같아 너무 감사히 쓰고 있다. 그리고 해당 이슈를 가서 보면 현재도 댓글이 계속 달리고 있는 것으로 보아 아직 사이드이펙트가 발생하는 듯 하다. 안정화 되고 나면 eslint9로 올려야지" - }, - { - "slug": "first-open-source-contribution", - "title": "오픈소스 첫 발걸음: Mantine PR 기여 후기", - "date": "2025-04-22", - "excerpt": "0. 프롤로그 \"내가 자주 사용하는 오픈 소스에 기여 해보고 싶다.\" 늘 마음 한켠에 있었지만, 다른 사람의 기여 후기를 보거나 기여 방법을 보아도 막막 했습니다. 그러던 중, 회사 프로젝트에서 Slider를 구현해야 할 일이 생겼습니다. 디자이너님께서 전달해주신 피그마 시안을 보자마자...", - "tags": [], - "series": "open-source", - "contentPreview": "0. 프롤로그 \"내가 자주 사용하는 오픈 소스에 기여 해보고 싶다.\" 늘 마음 한켠에 있었지만, 다른 사람의 기여 후기를 보거나 기여 방법을 보아도 막막 했습니다. 그러던 중, 회사 프로젝트에서 Slider를 구현해야 할 일이 생겼습니다. 디자이너님께서 전달해주신 피그마 시안을 보자마자 든 생각은 \"아... 망했다 저 기능 없는데\" 였습니다. --- 1. 상황 설명 저희 팀은 작년부터 자체 디자인 시스템을 구축하여 사용하고 있습니다. Mantine + panda-css 를 조합하여 사용 합니다. 따라서 디자인은 디자인 시스템의 컴포넌트를 활용하거나, mantine 공식 홈페이지를 참고하여 구현합니다. 그런데 전달받은 슬라이더 디자인 시안을 구현하는 데 필요한 특정 옵션이 Mantine 공식 문서에 없다는 사실을 발견했습니다. 그 순간 \"아... 이 기능 없는데 큰일이다.\" 라는 생각이 들었고, 곧바로 담당 PM과 디자이너에게 상황을 공유하며 도움을 요청했습니다. \"현재 이 기능은 Mantine에서 공식적으로 지원하지 않아 바로 구현하기는 어려워 보입니다. 일단 해당 기능을 제외하고 진행하는 방향으로 다시 논의해보는 것은 어떨까요?\" 다행히 제 의견이 수용되어, 해당 기능은 추후 다시 구현하기로 하고 1차 구현을 진행했습니다. 1차 구현 완료 후, 미구현 기능을 어떻게 구현할 수 있을지 고민하며 Mantine의 전체 코드를 내려받아 슬라이더 부분을 분석하기 시작했습니다. 코드를 분석하던 중 '분명 나만 이런 어려움을 겪는 것은 아닐 거야!' 라는 생각이 들어 GitHub에서 관련 이슈나 토론 글들을 찾아보았습니다. 하지만 비슷한 사례를 찾기 어려웠고, '아, 정말 나만 겪는 문제였나...' 하는 생각과 함께 다시 이슈 목록을 살펴보던 중, 슬라이더 관련 이슈 하나를 발견하게 되었습니다. 이슈 내용을 자세히 읽어보니, 이슈 제기자가 코드나 동작 방식에 대해 충분히 이해하지 못한 상태에서 문제를 제기한 것으로 보였습니다. 옆자리 동료와 함께 해당 이슈를 더 자세히 살펴보았습니다. 그러던 중 동료가 키보드로 슬라이더를 조작해보며 \"이슈 내용에는 키보드로는 정상 작동한다고 되어 있네요?\" 라고 말했습니다. 그 말을 듣는 순간, 제가 파악한 문제 해결 방법을 Mantine 코드에 적용할 수 있겠다는 확신이 들었습니다! 바로 이슈 댓글을 통해 메인테이너에게 제가 수정해도 괜찮은지 물었고, 다행히 긍정적인 답변을 받았습니다. --- 2. 이슈 파악 이슈 링크 - 문제 현상: 상태 변경과 함께 onChangeEnd 콜백이 제대로 업데이트되지 않음 - 발생 환경: Slider를 제어 컴포넌트(controlled component)로 사용할 때 발생 - 특이사항: - 마우스로 슬라이더를 조작할 때만 문제 발생 - 키보드로 조작할 때는 정상 작동 - 비제어 컴포넌트(uncontrolled)로 만들면 문제가 해결됨 - 원인 분석: Slider 컴포넌트 내부에서 상태 업데이트와 이벤트 핸들러 간의 동기화 문제로, React의 closure 특성과 관련된 이슈로 " - }, - { - "slug": "aws-ecs-rollback", - "title": "🚨3분만에 Next.js 서비스 장애 대응 대응하기: GitHub Actions + AWS ECS + CodeDeploy 롤백 시스템", - "date": "2025-04-03", - "excerpt": "0. 프롤로그 이번글에서는 지난번까지 구축한 ECS 환경에서, 오류 발생 시 애플리케이션을 안정적으로 롤백하는 방법에 대해 다뤄보겠습니다. 특히 GitHub Actions, AWS CodeDeploy를 활용하여 자동화된 배포 및 롤백 프로세스를 구현하는 방법을 중심으로 설명드릴 예정입니...", - "tags": [], - "series": "nextjs deploy", - "contentPreview": "0. 프롤로그 이번글에서는 지난번까지 구축한 ECS 환경에서, 오류 발생 시 애플리케이션을 안정적으로 롤백하는 방법에 대해 다뤄보겠습니다. 특히 GitHub Actions, AWS CodeDeploy를 활용하여 자동화된 배포 및 롤백 프로세스를 구현하는 방법을 중심으로 설명드릴 예정입니다. 문제 설명 평화로운 정기 배포의 날, 늘 그랬듯 배포 버튼을 누르고 커피 한 잔의 여유를 즐기며 배포 완료를 기다렸습니다. 커피를 다 마시고 나서야 배포 완료 메시지를 확인하며 \"오늘도 무사히 넘어갔구나\"라는 안도의 한숨을 내쉬었습니다. 그러나 약 2시간 후, 한 고객으로부터 \"특정 기능 사용 시 페이지가 다운된다\"는 신고가 접수되었습니다. 해당 기능은 당일 새롭게 배포된 것으로, 상황의 심각성을 더했습니다. 문제의 원인을 조사한 결과, 백엔드와 사전에 협의한 API 배포 일정이 내부 커뮤니케이션 오류로 인해 진행되지 않은 상태임을 확인할 수 있었습니다. 백엔드에서는 아직 개발이 진행 중이었으나, 프론트엔드에서는 이미 배포된 상황이었기에 긴급하게 롤백을 결정하게 되었습니다. 배포했던 브랜치를 재확인하고 빌드부터 배포까지 진행하는 데 총 30분이 소요되었습니다. 비록 당장의 위기는 해소되었으나, 이러한 상황이 재발될 경우를 대비하여 보다 신속하고 효율적으로 대응할 수 있는 시스템의 필요성을 절실히 느끼게 되었습니다. 이에 따라, 롤백 시스템의 개선을 결심하게 되었습니다. 1. 현재 문제 설정 1. 필요한 배포 버전 선정 및 결정 1. 필요한 버전을 노션에 작성된 배포트레커를 통해 찾는다. 2. 해당 merge pr를 찾는다. 3. 코드를 읽고 필요한 내용인지 검토 한다. ※ 특히 2번과 3번 단계에서는 소요 시간이 많고, 실수가 발생할 가능성도 있음을 유념해야 합니다. 2. 빌드 및 배포 1. 빌드 (약 6분 소요): 이미 ECR에 등록된 이미지가 존재함에도 불구하고, 상황에 따라 재활용하지 않고 새롭게 빌드를 진행 합니다. 2. 배포 (약 3분 소요): 빌드 완료 후 배포 절차를 진행합니다. 2. 개선 목표 esc 에 code deploy 가 연동 되어 있으면 task definition을 새로 만들어 올리면 해당 테스크를 새로 수행 합니다. 이를 이용하여 롤백을 구현 합니다. 1. 효율적인 버전 선정 및 롤백 절차 - 버전 관리를 체계화하여 필요한 배포 버전을 쉽고 빠르게 확인할 수 있도록 개선합니다. - 코드 검토, 빌드, 배포 전 과정에서 불필요한 시간 낭비를 줄이기 위해 자동화된 검증 절차를 추가합니다. 2. 배포 시간 단축 - ECR 이미지를 재활용할 수 있는 환경을 마련하여, 빌드 시간을 가능한 한 단축합니다. - 불필요한 프로세스를 제거하여 배포에 걸리는 시간을 줄입니다. 3. 문제 발생 시 빠른 대처 - 롤백이 신속히 실행될 수 있도록 기존 스크립트 및 설정을 간소화합니다. - 문제 발생 시 알림 및 관련 정보를 빠르게 제공하는 시스템을 연계 도입합니다. 3 개선 방법 1. 효율적인 버전 선정 및 롤백 절차 1. 버전 관리 시스템 개선 " - }, - { - "slug": "next-js-ecs-deploy", - "title": "ecs와 code deploy를 활용한 next.js 배포하기", - "date": "2025-04-01", - "excerpt": "0. 프롤로그 이전에는 next.js의 standalone과 turborepo의 --docker 옵션을 활용한 도커라이징 하는 방법을 정리하였습니다. 이번에는 aws의 ecs를 통해 컨테이너관리를 하고 code deploy를 통해 배포 하는 방법에 대해서 정리 해보겠습니다. --- 1....", - "tags": [], - "series": "nextjs deploy", - "contentPreview": "0. 프롤로그 이전에는 next.js의 standalone과 turborepo의 --docker 옵션을 활용한 도커라이징 하는 방법을 정리하였습니다. 이번에는 aws의 ecs를 통해 컨테이너관리를 하고 code deploy를 통해 배포 하는 방법에 대해서 정리 해보겠습니다. --- 1. AWS ECS란? AWS Elastic Container Service(ECS)는 완전관리형 컨테이너 오케스트레이션 서비스입니다. ECS를 사용하면 Docker 컨테이너를 손쉽게 실행 및 관리할 수 있으며, 클러스터를 구성하고 애플리케이션을 배포, 관리하는 데 도움을 줍니다. 2. ECS와 CodeDeploy를 이용한 배포 과정 아래는 ECS를 통해 컨테이너를 실행하고 CodeDeploy로 배포를 자동화하는 기본적인 과정을 정리한 내용입니다 프로젝트 구조 참고 1-2. 워크플로우 설명 1-2-1 git action event type 및 조건 확인 프로젝트 구조상 web1과 web2의 코드가 동시에 수정되는 경우가 있습니다. 이러한 상황에서는 개발 과정에 병목현상이 발생하여 일정에 차질이 생길 수 있습니다. 이를 방지하기 위해 특정 브랜치에만 배포되도록 조건문을 설정하였습니다. 1-2-2 docker build 및 ecr push task definition 이란 AWS ECS에서 태스크 정의(Task Definition)는 컨테이너화된 애플리케이션을 실행하기 위한 청사진 역할을 합니다. 다음과 같은 주요 기능과 역할을 수행합니다: task definition 정의 ECS 작업 정의(Task Definition) 주요 구성 요소 설명 containerDefinitions - name: 컨테이너의 식별자로 사용되는 이름 (web1) - image: 컨테이너에서 실행할 Docker 이미지의 URI - cpu: 컨테이너에 할당되는 CPU 단위 (0은 작업 수준의 CPU 제한만 적용) - memoryReservation: 컨테이너에 예약된 메모리 크기(MB) - portMappings: 컨테이너와 호스트 간의 포트 매핑 정의 - containerPort: 컨테이너 내부에서 사용하는 포트 (3000) - hostPort: 호스트에서 매핑될 포트 (0은 동적 포트 할당) - essential: true로 설정 시 이 컨테이너가 실패하면 작업 전체가 중지됨 - linuxParameters: Linux 특정 옵션 설정 - privileged: 컨테이너에 호스트 장치 접근 권한 부여 여부 - readonlyRootFilesystem: 루트 파일 시스템을 읽기 전용으로 마운트 여부 taskRoleArn 컨테이너가 AWS 서비스와 리소스에 접근할 때 사용하는 IAM 역할 executionRoleArn ECS가 컨테이너를 실행할 때 필요한 권한(ECR에서 이미지 풀링 등)을 가진 IAM 역할 networkMode 컨테이너의 네트워크 모드 (awsvpc는 각 작업에 고유한 ENI 제공) requiresCompatibilities 작업이 실행될 인프라 유형 정의 (EC2는 EC2" - }, - { - "slug": "turborepo-next.js-docker", - "title": "Turborepo 에서 next.js 도커라이징 하기", - "date": "2025-03-22", - "excerpt": "0. 프롤로그 이 글은 뮤즈라이브에서 웹 서비스 3개를 모노레포 구조에서 Turborepo의 공식 문서를 참조하여 Next.js의 standalone 모드와 Docker를 활용한 모노레포 환경 설정 및 최적화 방법을 설명합니다. 목표 - Next.js standalone 모드 설명 - ...", - "tags": [], - "series": "nextjs deploy", - "contentPreview": "0. 프롤로그 이 글은 뮤즈라이브에서 웹 서비스 3개를 모노레포 구조에서 Turborepo의 공식 문서를 참조하여 Next.js의 standalone 모드와 Docker를 활용한 모노레포 환경 설정 및 최적화 방법을 설명합니다. 목표 - Next.js standalone 모드 설명 - Turborepo를 활용한 모노레포 구성 이해 - Docker를 통해 효율적인 최적화 및 배포 방법 --- 1. Next.js standalone 란? Next.js standalone 모드는 애플리케이션을 컴파일하여 런타임에 불필요한 파일을 제거하고, 최적화된 상태로 제공하는 기능입니다. 이 모드는 애플리케이션을 더 작고 독립적인 단위로 패키징하여, 서버 실행 환경(Docker 등)에서 경량화와 성능 향상을 도모할 수 있습니다. 주요 특징 1. 최소화된 파일 크기: 번들링 과정에서 nodemodules 및 불필요한 파일을 배제하고, 필수 파일들만 포함합니다. 2. 독립적인 실행 환경: 애플리케이션 실행을 위해 Next.js 소스 코드와 관련된 종속 파일만 필요합니다. 3. 서버 배포 최적화: Docker와 같은 컨테이너 기반 시스템과 결합하여 보다 효과적인 배포가 가능해집니다. 4. 빠른 로딩 및 적은 리소스 사용: 실행 시 필요한 최소한의 파일과 리소스만 포함되기 때문에 초기화 속도와 성능이 향상됩니다. 5. CDN과 조합: 캐싱 기능 및 네트워크 요청 최적화를 통해 전 세계적으로 빠르고 안정적인 콘텐츠 제공이 가능합니다. 이 모드를 활용하면 Next.js 애플리케이션 배포 및 운영 관리를 더욱 효율적으로 할 수 있습니다. 2. 프로젝트 구조 프로젝트 구조 설명 apps 폴더는 실제 애플리케이션이 위치하는 디렉토리입니다. 여기에는 여러 개의 애플리케이션이 포함될 수 있으며, 이 예제에서는 web1, web2 애플리케이션이 있습니다. packages 폴더는 재사용 가능한 패키지들이 위치하는 디렉토리입니다. 이곳에는 ui 같은 공통으로 사용 가능한 모듈이나 라이브러리가 포함됩니다. - apps/web: 애플리케이션이 위치한 폴더로, Next.js 또는 다른 프레임워크 기반의 프로젝트가 포함될 수 있습니다. - package.json: 해당 애플리케이션의 종속성을 정의하는 파일입니다. - packages/ui: 공유 가능한 UI 컴포넌트 또는 유틸리티가 포함된 폴더입니다. - package.json: 공통 패키지의 종속성을 정의하는 파일입니다. - 최상위 package.json 및 package-lock.json: 프로젝트 전체를 관리하기 위한 종속성 정의 및 고정 파일들입니다. 이런 구조를 통해 각 애플리케이션과 공통 패키지를 독립적이면서도 효율적으로 관리할 수 있습니다. 3. Turborepo를 활용한 효율적인 도커라이징 방법 소개 (feat:공식문서) DockerFile 작성하기 의존성 문제 발생 - 패키지 설치 문제: apps/web1에 필요하지 않은 apps/web2의 의존성이 바뀌는 경우 불필요한 설치가 생깁니다. 또한 lock파일 또한 자주 바뀌" - }, - { - "slug": "nextjs-error", - "title": "Next.js로 우아하게 Error 핸들링하기", - "date": "2025-03-03", - "excerpt": "0. 프롤로그 이전까지는 javascript의 try catch과 React의 ErrorBoundary로 error 객체의 전파와 핸들링하는 방법에 대해 알아 보았습니다.
- - - https://blog.sangwook.dev/ - 2026-06-12 - 1.0 - - - https://blog.sangwook.dev/posts/ - 2026-06-12 - 0.8 - - - https://blog.sangwook.dev/about/ - 2026-06-12 - 0.7 - - - - https://blog.sangwook.dev/posts/typescript-domain-modeling-without-optional/ - 2026-03-16 - 0.6 - - - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-04-sourcemap/ - 2026-03-03 - 0.75 - - - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-03-bundling-scope/ - 2026-02-23 - 0.75 - - - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-02-ast-graph/ - 2026-02-17 - 0.75 - - - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-00-prologue/ - 2026-02-02 - 0.75 - - - https://blog.sangwook.dev/posts/no-one-asked-library-bundler-01-concept/ - 2026-02-02 - 0.75 - - - https://blog.sangwook.dev/posts/payment-system-architecture/ - 2026-01-24 - 0.6 - - - https://blog.sangwook.dev/posts/2025-retrospect/ - 2025-12-21 - 0.6 - - - https://blog.sangwook.dev/posts/2025-teoconf-presentation/ - 2025-12-11 - 0.6 - - - https://blog.sangwook.dev/posts/npm-deploy-series-0-prologue/ - 2025-11-30 - 0.6 - - - https://blog.sangwook.dev/posts/typescript-project-type-safe-refactor-with-typescript/ - 2025-11-06 - 0.6 - - - https://blog.sangwook.dev/posts/react-error-deign/ - 2025-10-14 - 0.6 - - - https://blog.sangwook.dev/posts/ai-opensource-contribution/ - 2025-09-07 - 0.8 - - - https://blog.sangwook.dev/posts/feconf-2025-lightning-speaker/ - 2025-09-02 - 0.6 - - - https://blog.sangwook.dev/posts/nodejs-contribution/ - 2025-08-10 - 0.8 - - - https://blog.sangwook.dev/posts/nextjs-contributor/ - 2025-08-05 - 0.8 - - - https://blog.sangwook.dev/posts/react-component-context-api-dropzone/ - 2025-07-30 - 0.6 - - - https://blog.sangwook.dev/posts/react-component-type-guard-button/ - 2025-06-30 - 0.6 - - - https://blog.sangwook.dev/posts/react-component-toast/ - 2025-06-30 - 0.6 - - - https://blog.sangwook.dev/posts/2025-mid-year-review/ - 2025-06-17 - 0.6 - - - https://blog.sangwook.dev/posts/typescript-project-domain-design/ - 2025-06-15 - 0.6 - - - https://blog.sangwook.dev/posts/typescript-project-service-design/ - 2025-06-08 - 0.6 - - - https://blog.sangwook.dev/posts/typescript-project-service-di-design/ - 2025-06-08 - 0.6 - - - https://blog.sangwook.dev/posts/typescript-project-api-design/ - 2025-06-01 - 0.6 - - - https://blog.sangwook.dev/posts/typescript-project-api-di-design/ - 2025-06-01 - 0.6 - - - https://blog.sangwook.dev/posts/typescript-project-design/ - 2025-05-05 - 0.6 - - - https://blog.sangwook.dev/posts/pnpm-eslint-not-working/ - 2025-05-01 - 0.6 - - - https://blog.sangwook.dev/posts/first-open-source-contribution/ - 2025-04-22 - 0.8 - - - https://blog.sangwook.dev/posts/aws-ecs-rollback/ - 2025-04-03 - 0.6 - - - https://blog.sangwook.dev/posts/next-js-ecs-deploy/ - 2025-04-01 - 0.6 - - - https://blog.sangwook.dev/posts/turborepo-next.js-docker/ - 2025-03-22 - 0.6 - - - https://blog.sangwook.dev/posts/nextjs-error/ - 2025-03-03 - 0.6 - - - https://blog.sangwook.dev/posts/react-error/ - 2025-03-02 - 0.6 - - - https://blog.sangwook.dev/posts/javascript-error/ - 2025-02-27 - 0.6 - - - https://blog.sangwook.dev/posts/next-middleware/ - 2025-02-26 - 0.6 - - - https://blog.sangwook.dev/posts/panda-css-1year-review/ - 2025-02-17 - 0.6 - - - https://blog.sangwook.dev/posts/adding-interaction-layers-to-components/ - 2025-02-10 - 0.6 - - - https://blog.sangwook.dev/posts/design-system-start/ - 2025-02-02 - 0.6 - - - https://blog.sangwook.dev/posts/simple-fsd-start/ - 2025-01-21 - 0.6 - - - https://blog.sangwook.dev/posts/reduce-server-dependency-clean-architecture/ - 2025-01-13 - 0.6 - - - https://blog.sangwook.dev/posts/2024-retrospect/ - 2024-12-23 - 0.6 - - \ No newline at end of file diff --git a/apps/next.js/package.json b/apps/next.js/package.json index 54873726..9fd8e5cf 100644 --- a/apps/next.js/package.json +++ b/apps/next.js/package.json @@ -16,8 +16,8 @@ }, "dependencies": { "next": "catalog:", - "react": "catalog:react19", - "react-dom": "catalog:react19", + "react": "catalog:", + "react-dom": "catalog:", "@design-system/ui": "workspace:^", "@design-system/ui-lib": "workspace:^" }, @@ -30,8 +30,8 @@ "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^14.6.1", "@types/node": "^25.8.0", - "@types/react": "catalog:react19", - "@types/react-dom": "catalog:react19", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", "@vitejs/plugin-react": "^5.0.4", "eslint": "^9", "eslint-config-next": "16.2.6", @@ -39,7 +39,7 @@ "eslint-plugin-react-hooks": "^5.1.0", "jsdom": "^27.0.0", "next-router-mock": "^0.9.13", - "typescript": "catalog:typescript5", + "typescript": "catalog:", "vitest": "^4.0.0-beta.15" } } diff --git a/apps/react/package.json b/apps/react/package.json index ecb7967b..eeb5c403 100644 --- a/apps/react/package.json +++ b/apps/react/package.json @@ -19,8 +19,8 @@ "@design-system/ui-lib": "workspace:^", "@package/core": "workspace:*", "@tanstack/react-query": "^5.100.10", - "react": "catalog:react19", - "react-dom": "catalog:react19", + "react": "catalog:", + "react-dom": "catalog:", "react-router": "^7.15.1" }, "devDependencies": { @@ -30,8 +30,8 @@ "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^14.6.1", "@types/node": "^25.8.0", - "@types/react": "catalog:react19", - "@types/react-dom": "catalog:react19", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", "@vitejs/plugin-react": "^5.0.4", "eslint": "^9.19.0", "eslint-plugin-react-hooks": "^5.0.0", @@ -39,7 +39,7 @@ "globals": "^17.6.0", "jsdom": "^29.1.1", "msw": "^2.7.6", - "typescript": "catalog:typescript5", + "typescript": "catalog:", "typescript-eslint": "^8.32.0", "vite": "^8.0.13", "vite-tsconfig-paths": "^6.0.0-beta.4", diff --git a/apps/react/tsconfig.app.json b/apps/react/tsconfig.app.json index 08040c58..b6d06859 100644 --- a/apps/react/tsconfig.app.json +++ b/apps/react/tsconfig.app.json @@ -19,7 +19,6 @@ "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, - "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@pages/*": ["./src/pages/*"], diff --git a/apps/socket-server/package.json b/apps/socket-server/package.json index 1e140c39..d452b60c 100644 --- a/apps/socket-server/package.json +++ b/apps/socket-server/package.json @@ -15,6 +15,6 @@ "dependencies": {}, "devDependencies": { "@types/node": "^25.8.0", - "typescript": "catalog:typescript5" + "typescript": "catalog:" } } diff --git a/apps/typescript/package.json b/apps/typescript/package.json index c563cb99..6727c8c4 100644 --- a/apps/typescript/package.json +++ b/apps/typescript/package.json @@ -15,7 +15,7 @@ "@package/config": "workspace:*", "@package/core": "workspace:*", "msw": "^2.7.6", - "typescript": "catalog:typescript5", + "typescript": "catalog:", "vitest": "^4.0.0-beta.15" } } diff --git a/package.json b/package.json index 5006f6b2..0341282f 100644 --- a/package.json +++ b/package.json @@ -16,18 +16,19 @@ "blog-build": "turbo run build --filter=@blog/web", "socket-server": "turbo run dev --filter=socket-server", "socket": "concurrently \"pnpm socket-server\" \"pnpm react\"", + "clean": "pnpm clean:dist && pnpm clean:modules", + "clean:dist": "find . -name node_modules -prune -o -type d '(' -name dist -o -name .next -o -name out -o -name .turbo ')' -prune -exec rm -rf {} +", + "clean:modules": "find . -name node_modules -type d -prune -exec rm -rf {} +", "prepare": "lefthook install" }, "devDependencies": { "lefthook": "^2.1.6", - "prettier": "^3.5.0", - "turbo": "^2.5.3" + "prettier": "^3.8.4", + "turbo": "^2.9.18", + "concurrently": "^10.0.3" }, "packageManager": "pnpm@11.6.0", "engines": { - "node": ">=22" - }, - "dependencies": { - "concurrently": "^9.2.0" + "node": ">=24" } } diff --git a/packages/@design-system/ui/package.json b/packages/@design-system/ui/package.json index 3e748ce1..ed421c95 100644 --- a/packages/@design-system/ui/package.json +++ b/packages/@design-system/ui/package.json @@ -3,8 +3,8 @@ "version": "0.0.1", "private": true, "type": "module", - "types": "./dist/index.d.ts", - "main": "./dist/index.js", + "types": "./dist/index.d.mts", + "main": "./dist/index.mjs", "exports": { ".": "./src/index.ts", "./preset": "./src/preset.ts", @@ -13,25 +13,25 @@ "publishConfig": { "exports": { ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js" + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs" }, "./preset": { - "types": "./dist/preset.d.ts", - "import": "./dist/preset.js" + "types": "./dist/preset.d.mts", + "import": "./dist/preset.mjs" }, "./blog-preset": { - "types": "./dist/blog-preset.d.ts", - "import": "./dist/blog-preset.js" + "types": "./dist/blog-preset.d.mts", + "import": "./dist/blog-preset.mjs" } } }, "scripts": { "prepare": "pnpm panda codegen && pnpm build", "codegen": "panda codegen", - "build": "tsup", + "build": "tsdown", "release": "pnpm panda prepare && pnpm build && pnpm publish", - "build-fast": "tsup --no-dts", + "build-fast": "tsdown --no-dts", "dev": "pnpm build-fast --watch", "fmt": "prettier --write ." }, @@ -39,20 +39,20 @@ "dist" ], "dependencies": { - "@design-system/ui-lib": "workspace:^", - "tsup": "8.4.0", - "typescript": "5.8.3" + "@design-system/ui-lib": "workspace:^" }, - "packageManager": "pnpm@10.10.0", "devDependencies": { "@pandacss/dev": "catalog:", - "@types/react": "catalog:react19", - "@types/react-dom": "catalog:react19", - "react": "catalog:react19", - "react-dom": "catalog:react19" + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "react": "catalog:", + "react-dom": "catalog:", + "tsdown": "0.22.2", + "typescript": "catalog:" }, "peerDependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0" + "@pandacss/dev": "catalog:", + "react": "catalog:", + "react-dom": "catalog:" } } diff --git a/packages/@design-system/ui/tsup.config.ts b/packages/@design-system/ui/tsdown.config.ts similarity index 83% rename from packages/@design-system/ui/tsup.config.ts rename to packages/@design-system/ui/tsdown.config.ts index a4de986f..7335265e 100644 --- a/packages/@design-system/ui/tsup.config.ts +++ b/packages/@design-system/ui/tsdown.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'tsup'; +import { defineConfig } from 'tsdown'; export default defineConfig({ entry: { diff --git a/packages/@package/bundler/package.json b/packages/@package/bundler/package.json index c8dd900f..7d07a1df 100644 --- a/packages/@package/bundler/package.json +++ b/packages/@package/bundler/package.json @@ -5,25 +5,30 @@ "type": "module", "exports": { ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js", - "require": "./dist/index.cjs" + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { "prepare": "pnpm build", - "build": "tsup", - "dev": "tsup --watch" + "build": "tsdown", + "dev": "tsdown --watch" }, "bin": { - "minibundler": "./dist/cli.js" + "minibundler": "./dist/cli.mjs" }, "devDependencies": { "@types/estree": "^1.0.8", "@types/node": "^25.8.0", - "tsup": "8.4.0", + "tsdown": "0.22.2", "tsx": "^4.22.0", - "typescript": "5.9.3" + "typescript": "catalog:" }, "dependencies": { "acorn": "^8.14.0", diff --git a/packages/@package/bundler/tsup.config.ts b/packages/@package/bundler/tsdown.config.ts similarity index 74% rename from packages/@package/bundler/tsup.config.ts rename to packages/@package/bundler/tsdown.config.ts index 2679d5fd..e71f5821 100644 --- a/packages/@package/bundler/tsup.config.ts +++ b/packages/@package/bundler/tsdown.config.ts @@ -1,8 +1,9 @@ -import { defineConfig } from 'tsup'; +import { defineConfig } from 'tsdown'; export default defineConfig({ entry: ['src/index.ts', 'src/cli.ts'], format: ['esm', 'cjs'], + platform: 'node', target: 'node24', clean: true, dts: true, diff --git a/packages/@package/core/package.json b/packages/@package/core/package.json index 10a2af21..a6fb8302 100644 --- a/packages/@package/core/package.json +++ b/packages/@package/core/package.json @@ -10,9 +10,8 @@ "keywords": [], "author": "", "license": "ISC", - "packageManager": "pnpm@10.4.1", "devDependencies": { - "typescript": "catalog:typescript5", + "typescript": "catalog:", "@package/config": "workspace:*" } } diff --git a/packages/@package/sample-lib/package.json b/packages/@package/sample-lib/package.json index f1d1d5ff..d5f36d39 100644 --- a/packages/@package/sample-lib/package.json +++ b/packages/@package/sample-lib/package.json @@ -17,14 +17,14 @@ "build:types": "tsc --emitDeclarationOnly" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "react": ">=19", + "react-dom": ">=19" }, "devDependencies": { "@package/bundler": "workspace:*", - "react": "^19.2.4", - "react-dom": "^19.2.4", + "react": "catalog:", + "react-dom": "catalog:", "tsx": "^4.22.0", - "typescript": "^5.9.3" + "typescript": "catalog:" } } diff --git a/packages/@package/sample-lib/tsconfig.json b/packages/@package/sample-lib/tsconfig.json index 49b19b11..95d069b3 100644 --- a/packages/@package/sample-lib/tsconfig.json +++ b/packages/@package/sample-lib/tsconfig.json @@ -8,6 +8,7 @@ "declaration": true, "emitDeclarationOnly": true, "outDir": "./dist", + "rootDir": "./src", "allowJs": true }, "include": ["src/**/*"] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1dcf6d32..b298228d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,26 +9,24 @@ catalogs: '@pandacss/dev': specifier: 1.11.1 version: 1.11.1 + '@types/react': + specifier: 19.2.17 + version: 19.2.17 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3 next: specifier: 16.2.6 version: 16.2.6 - react19: - '@types/react': - specifier: ^19.2.14 - version: 19.2.15 - '@types/react-dom': - specifier: ^19.2.0 - version: 19.2.0 react: - specifier: ^19.3.0-canary-a757cb76-20251002 - version: 19.3.0-canary-a757cb76-20251002 + specifier: 19.2.7 + version: 19.2.7 react-dom: - specifier: ^19.3.0-canary-a757cb76-20251002 - version: 19.3.0-canary-a757cb76-20251002 - typescript5: + specifier: 19.2.7 + version: 19.2.7 typescript: - specifier: 5.8.3 - version: 5.8.3 + specifier: 6.0.3 + version: 6.0.3 overrides: '@babel/plugin-transform-modules-systemjs': 7.29.4 @@ -49,27 +47,25 @@ overrides: picomatch@4: 4.0.4 postcss: 8.5.14 qs@6: 6.15.1 - rollup@4: 4.60.4 tough-cookie@2: 4.1.4 uuid@11: 11.1.1 importers: .: - dependencies: - concurrently: - specifier: ^9.2.0 - version: 9.2.1 devDependencies: + concurrently: + specifier: ^10.0.3 + version: 10.0.3 lefthook: specifier: ^2.1.6 version: 2.1.6 prettier: - specifier: ^3.5.0 - version: 3.8.1 + specifier: ^3.8.4 + version: 3.8.4 turbo: - specifier: ^2.5.3 - version: 2.9.5 + specifier: ^2.9.18 + version: 2.9.18 apps/blog/web: dependencies: @@ -81,19 +77,19 @@ importers: version: link:../../../packages/@design-system/ui-lib '@giscus/react': specifier: ^3.1.0 - version: 3.1.0(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 3.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mdx-js/loader': specifier: ^3.1.0 version: 3.1.1(acorn@8.16.0) '@mdx-js/react': specifier: ^3.1.0 - version: 3.1.1(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002) + version: 3.1.1(@types/react@19.2.17)(react@19.2.7) '@next/mdx': specifier: ^16.2.6 - version: 16.2.6(@mdx-js/loader@3.1.1(acorn@8.16.0))(@mdx-js/react@3.1.1(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002)) + version: 16.2.6(@mdx-js/loader@3.1.1(acorn@8.16.0))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7)) '@next/third-parties': specifier: ^16.2.6 - version: 16.2.6(next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 16.2.6(next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7) '@ssgoi/react': specifier: 6.4.0 version: 6.4.0 @@ -102,13 +98,13 @@ importers: version: 2.103.0 '@tanstack/react-query': specifier: ^5.100.10 - version: 5.100.14(react@19.3.0-canary-a757cb76-20251002) + version: 5.100.14(react@19.2.7) gray-matter: specifier: ^4.0.3 version: 4.0.3 lucide-react: specifier: ^0.563.0 - version: 0.563.0(react@19.3.0-canary-a757cb76-20251002) + version: 0.563.0(react@19.2.7) mermaid: specifier: ^11.15.0 version: 11.15.0 @@ -117,34 +113,34 @@ importers: version: 3.0.2 motion: specifier: ^12.29.2 - version: 12.38.0(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 12.38.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) nuqs: specifier: ^2.8.8 - version: 2.8.9(next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002))(react-router@7.15.1(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 2.8.9(next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7) pretendard: specifier: ^1.3.9 version: 1.3.9 react: - specifier: catalog:react19 - version: 19.3.0-canary-a757cb76-20251002 + specifier: 'catalog:' + version: 19.2.7 react-dom: - specifier: catalog:react19 - version: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + specifier: 'catalog:' + version: 19.2.7(react@19.2.7) react-markdown: specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002) + version: 10.1.0(@types/react@19.2.17)(react@19.2.7) react-medium-image-zoom: specifier: ^5.4.5 - version: 5.4.5(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 5.4.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react-syntax-highlighter: specifier: ^16.1.0 - version: 16.1.1(react@19.3.0-canary-a757cb76-20251002) + version: 16.1.1(react@19.2.7) recharts: specifier: ^3.7.0 - version: 3.8.1(@types/react@19.2.15)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react-is@18.3.1)(react@19.3.0-canary-a757cb76-20251002)(redux@5.0.1) + version: 3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@18.3.1)(react@19.2.7)(redux@5.0.1) rehype-raw: specifier: ^7.0.0 version: 7.0.0 @@ -160,7 +156,7 @@ importers: version: 3.3.5 '@pandacss/dev': specifier: 'catalog:' - version: 1.11.1(jsdom@29.1.1)(typescript@5.8.3) + version: 1.11.1(jsdom@29.1.1)(typescript@6.0.3) '@resvg/resvg-js': specifier: ^2.6.2 version: 2.6.2 @@ -172,7 +168,7 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.2.0 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.0(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@testing-library/user-event': specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.1) @@ -186,11 +182,11 @@ importers: specifier: ^25.8.0 version: 25.9.1 '@types/react': - specifier: catalog:react19 - version: 19.2.15 + specifier: 'catalog:' + version: 19.2.17 '@types/react-dom': - specifier: catalog:react19 - version: 19.2.0(@types/react@19.2.15) + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.17) '@types/react-syntax-highlighter': specifier: ^15.5.13 version: 15.5.13 @@ -211,7 +207,7 @@ importers: version: 9.39.4(jiti@2.4.2) eslint-config-next: specifier: 16.2.6 - version: 16.2.6(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) + version: 16.2.6(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) eslint-plugin-react-hooks: specifier: ^7.0.0 version: 7.0.1(eslint@9.39.4(jiti@2.4.2)) @@ -228,11 +224,11 @@ importers: specifier: ^4.22.0 version: 4.22.3 typescript: - specifier: catalog:typescript5 - version: 5.8.3 + specifier: 'catalog:' + version: 6.0.3 vitest: specifier: ^4.0.0-beta.15 - version: 4.1.4(@types/node@25.9.1)(jsdom@29.1.1)(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) + version: 4.1.4(@types/node@25.9.1)(jsdom@29.1.1)(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) apps/next.js: dependencies: @@ -244,13 +240,13 @@ importers: version: link:../../packages/@design-system/ui-lib next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: - specifier: catalog:react19 - version: 19.3.0-canary-a757cb76-20251002 + specifier: 'catalog:' + version: 19.2.7 react-dom: - specifier: catalog:react19 - version: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + specifier: 'catalog:' + version: 19.2.7(react@19.2.7) devDependencies: '@eslint/eslintrc': specifier: ^3 @@ -260,7 +256,7 @@ importers: version: 16.2.6 '@pandacss/dev': specifier: 'catalog:' - version: 1.11.1(jsdom@27.4.0)(typescript@5.8.3) + version: 1.11.1(jsdom@27.4.0)(typescript@6.0.3) '@testing-library/dom': specifier: ^10.4.0 version: 10.4.1 @@ -269,7 +265,7 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.2.0 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.0(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@testing-library/user-event': specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.1) @@ -277,11 +273,11 @@ importers: specifier: ^25.8.0 version: 25.9.1 '@types/react': - specifier: catalog:react19 - version: 19.2.15 + specifier: 'catalog:' + version: 19.2.17 '@types/react-dom': - specifier: catalog:react19 - version: 19.2.0(@types/react@19.2.15) + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.2.0(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) @@ -290,7 +286,7 @@ importers: version: 9.39.4(jiti@2.4.2) eslint-config-next: specifier: 16.2.6 - version: 16.2.6(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) + version: 16.2.6(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) eslint-plugin-react: specifier: ^7.37.4 version: 7.37.5(eslint@9.39.4(jiti@2.4.2)) @@ -302,13 +298,13 @@ importers: version: 27.4.0 next-router-mock: specifier: ^0.9.13 - version: 0.9.13(next@16.2.6(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 0.9.13(next@16.2.6(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7) typescript: - specifier: catalog:typescript5 - version: 5.8.3 + specifier: 'catalog:' + version: 6.0.3 vitest: specifier: ^4.0.0-beta.15 - version: 4.1.4(@types/node@25.9.1)(jsdom@27.4.0)(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) + version: 4.1.4(@types/node@25.9.1)(jsdom@27.4.0)(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) apps/react: dependencies: @@ -323,29 +319,29 @@ importers: version: link:../../packages/@package/core '@tanstack/react-query': specifier: ^5.100.10 - version: 5.100.14(react@19.3.0-canary-a757cb76-20251002) + version: 5.100.14(react@19.2.7) react: - specifier: catalog:react19 - version: 19.3.0-canary-a757cb76-20251002 + specifier: 'catalog:' + version: 19.2.7 react-dom: - specifier: catalog:react19 - version: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + specifier: 'catalog:' + version: 19.2.7(react@19.2.7) react-router: specifier: ^7.15.1 - version: 7.15.1(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) devDependencies: '@eslint/js': specifier: ^9.19.0 version: 9.39.4 '@pandacss/dev': specifier: 'catalog:' - version: 1.11.1(jsdom@29.1.1)(typescript@5.8.3) + version: 1.11.1(jsdom@29.1.1)(typescript@6.0.3) '@testing-library/jest-dom': specifier: ^6.6.3 version: 6.9.1 '@testing-library/react': specifier: ^16.2.0 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.0(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@testing-library/user-event': specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.1) @@ -353,11 +349,11 @@ importers: specifier: ^25.8.0 version: 25.9.1 '@types/react': - specifier: catalog:react19 - version: 19.2.15 + specifier: 'catalog:' + version: 19.2.17 '@types/react-dom': - specifier: catalog:react19 - version: 19.2.0(@types/react@19.2.15) + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^5.0.4 version: 5.2.0(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) @@ -378,22 +374,22 @@ importers: version: 29.1.1 msw: specifier: ^2.7.6 - version: 2.13.2(@types/node@25.9.1)(typescript@5.8.3) + version: 2.13.2(@types/node@25.9.1)(typescript@6.0.3) typescript: - specifier: catalog:typescript5 - version: 5.8.3 + specifier: 'catalog:' + version: 6.0.3 typescript-eslint: specifier: ^8.32.0 - version: 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) + version: 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) vite: specifier: ^8.0.13 version: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3) vite-tsconfig-paths: specifier: ^6.0.0-beta.4 - version: 6.1.1(typescript@5.8.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) + version: 6.1.1(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) vitest: specifier: ^4.0.0-beta.15 - version: 4.1.4(@types/node@25.9.1)(jsdom@29.1.1)(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) + version: 4.1.4(@types/node@25.9.1)(jsdom@29.1.1)(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) apps/socket-server: devDependencies: @@ -401,8 +397,8 @@ importers: specifier: ^25.8.0 version: 25.9.1 typescript: - specifier: catalog:typescript5 - version: 5.8.3 + specifier: 'catalog:' + version: 6.0.3 apps/typescript: devDependencies: @@ -414,41 +410,41 @@ importers: version: link:../../packages/@package/core msw: specifier: ^2.7.6 - version: 2.13.2(@types/node@25.9.1)(typescript@5.8.3) + version: 2.13.2(@types/node@25.9.1)(typescript@6.0.3) typescript: - specifier: catalog:typescript5 - version: 5.8.3 + specifier: 'catalog:' + version: 6.0.3 vitest: specifier: ^4.0.0-beta.15 - version: 4.1.4(@types/node@25.9.1)(jsdom@29.1.1)(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) + version: 4.1.4(@types/node@25.9.1)(jsdom@29.1.1)(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) packages/@design-system/ui: dependencies: '@design-system/ui-lib': specifier: workspace:^ version: link:../ui-lib - tsup: - specifier: 8.4.0 - version: 8.4.0(jiti@2.4.2)(postcss@8.5.14)(tsx@4.22.3)(typescript@5.8.3) - typescript: - specifier: 5.8.3 - version: 5.8.3 devDependencies: '@pandacss/dev': specifier: 'catalog:' - version: 1.11.1(typescript@5.8.3) + version: 1.11.1(typescript@6.0.3) '@types/react': - specifier: catalog:react19 - version: 19.2.15 + specifier: 'catalog:' + version: 19.2.17 '@types/react-dom': - specifier: catalog:react19 - version: 19.2.0(@types/react@19.2.15) + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.17) react: - specifier: catalog:react19 - version: 19.3.0-canary-a757cb76-20251002 + specifier: 'catalog:' + version: 19.2.7 react-dom: - specifier: catalog:react19 - version: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + specifier: 'catalog:' + version: 19.2.7(react@19.2.7) + tsdown: + specifier: 0.22.2 + version: 0.22.2(tsx@4.22.3)(typescript@6.0.3) + typescript: + specifier: 'catalog:' + version: 6.0.3 packages/@design-system/ui-lib: dependencies: @@ -471,15 +467,15 @@ importers: '@types/node': specifier: ^25.8.0 version: 25.9.1 - tsup: - specifier: 8.4.0 - version: 8.4.0(jiti@2.4.2)(postcss@8.5.14)(tsx@4.22.3)(typescript@5.9.3) + tsdown: + specifier: 0.22.2 + version: 0.22.2(tsx@4.22.3)(typescript@6.0.3) tsx: specifier: ^4.22.0 version: 4.22.3 typescript: - specifier: 5.9.3 - version: 5.9.3 + specifier: 'catalog:' + version: 6.0.3 packages/@package/bundler-playground: dependencies: @@ -501,8 +497,8 @@ importers: specifier: workspace:* version: link:../config typescript: - specifier: catalog:typescript5 - version: 5.8.3 + specifier: 'catalog:' + version: 6.0.3 packages/@package/sample-lib: devDependencies: @@ -510,17 +506,17 @@ importers: specifier: workspace:* version: link:../bundler react: - specifier: ^19.2.4 - version: 19.2.5 + specifier: 'catalog:' + version: 19.2.7 react-dom: - specifier: ^19.2.4 - version: 19.2.5(react@19.2.5) + specifier: 'catalog:' + version: 19.2.7(react@19.2.7) tsx: specifier: ^4.22.0 version: 4.22.3 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: 'catalog:' + version: 6.0.3 packages: @@ -570,6 +566,10 @@ packages: resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} + '@babel/generator@8.0.0-rc.6': + resolution: {integrity: sha512-6mIzgVK8DgEzvIapoQwhXTMnnkuE4STQmVv9H03i/tZ2ml8oev3TRvZJgTenK2Bsq0YWNtzOrFdTyNzCMFtjJQ==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/helper-compilation-targets@7.28.6': resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} @@ -596,10 +596,18 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@8.0.0-rc.6': + resolution: {integrity: sha512-BCkFy+zN6kXQed3YOT7aJl93NfDSzQc3pBfsvTVPs9gU9X3V0aefEF5kwBT0E+mDWH9QgKaZstYUQN9VdQZT4g==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@8.0.0-rc.6': + resolution: {integrity: sha512-nVJ+1JcCgntv8d78rRo++o2wuODT0Irknx2BF8Np4Ft2CRgjLqIs4qzSZ8b66yGbBdMWGmZBO9WEZv1hhNiSpg==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -613,6 +621,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@8.0.0-rc.6': + resolution: {integrity: sha512-rOS8IpdO7mQELkTPlCsTgPejO0bFuZdEDCGQJouYbYf9e1FLTym7Fei2pEjq8q7MWbX0ravcd7QQYKs1TxOuog==} + engines: {node: ^22.18.0 || >=24.11.0} + hasBin: true + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} @@ -641,6 +654,10 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babel/types@8.0.0-rc.6': + resolution: {integrity: sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw==} + engines: {node: ^22.18.0 || >=24.11.0} + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -744,15 +761,24 @@ packages: '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/core@1.11.0': + resolution: {integrity: sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==} + '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.11.0': + resolution: {integrity: sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==} + '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} @@ -1347,10 +1373,6 @@ packages: '@types/node': optional: true - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -1421,6 +1443,12 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@next/env@16.2.6': resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==} @@ -1524,6 +1552,9 @@ packages: '@oxc-project/types@0.132.0': resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} + '@oxc-project/types@0.135.0': + resolution: {integrity: sha512-wR+xRdFkUBMvcAjBJ2q2kcZM6d+DKu2NgoOyxZgYwZdLhmiv6+rnO8PZ/P68kMiZtIKm+pW7zyEJ4kSOs0vo+Q==} + '@pandacss/config@1.11.1': resolution: {integrity: sha512-8f+pJfwDBlTgXqDKoTa3UFmiIZ4YYQvt5BPYQfD93xjvBPJBwdQl7P49obhSp/nkt13nl2MZRW+dtmrVQfz6OQ==} @@ -1585,9 +1616,8 @@ packages: '@pandacss/types@1.11.1': resolution: {integrity: sha512-VkigbeCwlDyyMBlQeRwOMLshSRjNB/2HqvfZvaVXT4+5miAYUAKeQDR88UqUL2aqPWkltTxMVEwBnqSQdC8+jw==} - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} + '@quansync/fs@1.0.0': + resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} '@reduxjs/toolkit@2.11.2': resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==} @@ -1686,30 +1716,60 @@ packages: cpu: [arm64] os: [android] + '@rolldown/binding-android-arm64@1.1.1': + resolution: {integrity: sha512-BLf9Wak/gfwVb7NQTQW4wBgL3oAfPy7ArEkhwV543OVw/uY6B47z5xYsqPSZ9PDOorvURPinws6ThaFuNgGLgA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-darwin-arm64@1.0.2': resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-arm64@1.1.1': + resolution: {integrity: sha512-rRZRPy/Ynb+Mxu0O6tfPldHeDgAn0sRij+IOUy6sFdUlv3hArGW/DloE3GfAxtqpOJuRNgF74Nr5gM4xBeU2jQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.0.2': resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@rolldown/binding-darwin-x64@1.1.1': + resolution: {integrity: sha512-/MtefPxhKPyWWFM8L45OWiEqRf+eSU2Qv9ZAyTaoZOoGcoPKxbbhjTJO2/U2IThv0uDZ4NWHc3/oTsR6IEOtww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-freebsd-x64@1.0.2': resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@rolldown/binding-freebsd-x64@1.1.1': + resolution: {integrity: sha512-202K+cpIi1kx/Zn7AtxBi4LTXSY67Aszb2K9rNsuW7FeBeh0nqoNmYLOSZidV0p88VPBzMmTZcHAdPNo3kRYzQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.1.1': + resolution: {integrity: sha512-wl9NfeXNUwrXtUc063tddmZFUI6qiNs1CNOwni0OL4vC7MqVSYugra3ZgtDmtVy8e0DluJTENmzIv2BwqLzT4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.0.2': resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1717,6 +1777,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.1.1': + resolution: {integrity: sha512-at2EO4o7D/PJLC4Xik16bU4CcjQE2tSv1LfqMA0TRYQYQihRm3gZeDB8xaX28A9SFedibcAk5DeMCKt4REKG0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.0.2': resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1724,6 +1791,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.1.1': + resolution: {integrity: sha512-5PUjZx366h9tkJTPJF5eibxOlK3sGoeRiBJLLjjEB5/kLDuhr6qB3LkhqLz1smXNgsX+pBhnbcJBrPE30HznAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.0.2': resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1731,6 +1805,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.1.1': + resolution: {integrity: sha512-1WK84XPeio3tjP1sM/TMXiC0G1i1iq1qGZ71KfNQjEFLU1kwD+Cv5T8nGySg/JUFwLbaScu6ve9DmeXlmqpkFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.0.2': resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1738,6 +1819,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.1.1': + resolution: {integrity: sha512-1nS1X5z1uMJ369RU25hTpKCFvUwXZp12dIzlzk4S+UxCTcSVGsAE6tzkOSufv/7jnmAtK0ZlrsJxh2fGmsnVSw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.2': resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1745,6 +1833,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.1.1': + resolution: {integrity: sha512-NwX/wspnq4vYyMFsqbYvzums3ki/Tk8FZbMzMAovPDp3OfLeYKby/D+9osokadXuYEV3OvpeHlwnr/bG8QMixA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.0.2': resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1752,173 +1847,65 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-x64-musl@1.1.1': + resolution: {integrity: sha512-+n46LhDrJFQM+229y4oXtVpj1G50U/+XuHMlpnisFTEXhrg9f/YIjp/HymX+PVJjBEr7XHRs3CFLelV464pqwA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-openharmony-arm64@1.0.2': resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.1.1': + resolution: {integrity: sha512-qGwEu47zOWYo7LdRHhCWTNhzwGtxXpdY6CERs8QEOqC0PXGGics/e3vHnyEUKt8xK6YkbZXFUCeklrpB6js8ag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.0.2': resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] + '@rolldown/binding-wasm32-wasi@1.1.1': + resolution: {integrity: sha512-qczfgEH8u0wHGGOXtA7UMAybNKuQjjEXairyQaw4WzjiMztfbgatG1h4OKays/smhtwbWltpKCRGtVhU6h40Sg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + '@rolldown/binding-win32-arm64-msvc@1.0.2': resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.1.1': + resolution: {integrity: sha512-4psXSh63mSbwJF+mB8/9yfUUEzBiHYcUjxa32EO9ZwKy0Ypwjcg4F10D8SvVXgd+isy2UUUjF9HJJnDu1T/4Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.2': resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.1.1': + resolution: {integrity: sha512-MUvC/HLXVjzkQkWiExdVTEEWf0py+GfWm8WKSZsekG3ih6a21iy0BHPF07X3JIf3ifoklZXTIaHTLPBgH1C3dw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/pluginutils@1.0.0-rc.3': resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rollup/rollup-android-arm-eabi@4.60.4': - resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.60.4': - resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.60.4': - resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.60.4': - resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.60.4': - resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.60.4': - resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': - resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-musleabihf@4.60.4': - resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.60.4': - resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm64-musl@4.60.4': - resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-loong64-gnu@4.60.4': - resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.60.4': - resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.60.4': - resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-ppc64-musl@4.60.4': - resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.60.4': - resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.60.4': - resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.60.4': - resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.60.4': - resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-musl@4.60.4': - resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rollup/rollup-openbsd-x64@4.60.4': - resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.60.4': - resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.60.4': - resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.60.4': - resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.60.4': - resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.60.4': - resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} - cpu: [x64] - os: [win32] - '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -2014,33 +2001,33 @@ packages: '@ts-morph/common@0.29.0': resolution: {integrity: sha512-35oUmphHbJvQ/+UTwFNme/t2p3FoKiGJ5auTjjpNTop2dyREspirjMy82PLSC1pnDJ8ah1GU98hwpVt64YXQsg==} - '@turbo/darwin-64@2.9.5': - resolution: {integrity: sha512-qPxhKsLMQP+9+dsmPgAGidi5uNifD4AoAOnEnljab3Qgn0QZRR31Hp+/CgW3Ia5AanWj6JuLLTBYvuQj4mqTWg==} + '@turbo/darwin-64@2.9.18': + resolution: {integrity: sha512-9f27peFu16ur8c0v9nUFUEyBnbKuuFsUTjHFWfmwGfzySBXbHwzU44QhZon6Mznz0cHsIr3984NQj/bVrnGSRw==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.9.5': - resolution: {integrity: sha512-vkF/9F/l3aWd4bHxTui5Hh0F5xrTZ4e3rbBsc57zA6O8gNbmHN3B6eZ5psAIP2CnJRZ8ZxRjV3WZHeNXMXkPBw==} + '@turbo/darwin-arm64@2.9.18': + resolution: {integrity: sha512-9A6TMRq/Ib+QnbhLlgkhOm+624wO4pzSQ/yQviQfWHOlFvaYxdnIAYmu2H6TS6y7kSVL0DvzNe04NbESTOzFVQ==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.9.5': - resolution: {integrity: sha512-z/Get5NUaUxm5HSGFqVMICDRjFNsCUhSc4wnFa/PP1QD0NXCjr7bu9a2EM6md/KMCBW0Qe393Ac+UM7/ryDDTw==} + '@turbo/linux-64@2.9.18': + resolution: {integrity: sha512-zCdIDtz69AnbYh913elJRRoF3QY5aa2HNnf+4rAkc7bQ+tWujiDkCNV7stazOUPggaDvhKIf2Z87qHftTeXSkw==} cpu: [x64] os: [linux] - '@turbo/linux-arm64@2.9.5': - resolution: {integrity: sha512-jyBifaNoI5/NheyswomiZXJvjdAdvT7hDRYzQ4meP0DKGvpXUjnqsD+4/J2YSDQ34OHxFkL30FnSCUIVOh2PHw==} + '@turbo/linux-arm64@2.9.18': + resolution: {integrity: sha512-Va1kXI04naMgYwqv/5Dfa36dTDx8015U7oaQAjrXa45ua9OoFjSV4OmvkML4EmXvUclQHCiBRbY8bvd0jV7eAg==} cpu: [arm64] os: [linux] - '@turbo/windows-64@2.9.5': - resolution: {integrity: sha512-ph24K5uPtvo7UfuyDXnBiB/8XvrO+RQWbbw5zkA/bVNoy9HDiNoIJJj3s62MxT9tjEb6DnPje5PXSz1UR7QAyg==} + '@turbo/windows-64@2.9.18': + resolution: {integrity: sha512-m0kDhZANxSNz9ck1ybogFscHabriAsp4eDFNrN/1H5WrgTF7b3VlcPZnhuO3v2+E2KnCbeAc+UUT10BZZHdDKw==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.9.5': - resolution: {integrity: sha512-6c5RccT/+iR39SdT1G5HyZaD2n57W77o+l0TTfxG/cVlhV94Acyg2gTQW7zUOhW1BeQpBjHzu9x8yVBZwrHh7g==} + '@turbo/windows-arm64@2.9.18': + resolution: {integrity: sha512-nUdR8WqoomUys9iIQmG45TMiizJ+5BV8egSeLLZba/AWblyp3fVBcIH1kSE58OtK4g2YzbMJEth6Ttv9w5rqMA==} cpu: [arm64] os: [win32] @@ -2182,6 +2169,9 @@ packages: '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + '@types/jsesc@2.5.1': + resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2209,8 +2199,8 @@ packages: '@types/prismjs@1.26.5': resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} - '@types/react-dom@19.2.0': - resolution: {integrity: sha512-brtBs0MnE9SMx7px208g39lRmC5uHZs96caOJfTjFcYSLHNamvaSMfJNagChVNkup2SdtOxKX1FDBkRSJe1ZAg==} + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: '@types/react': ^19.2.0 @@ -2220,6 +2210,9 @@ packages: '@types/react@19.2.15': resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} @@ -2402,8 +2395,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} ansi-styles@4.3.0: @@ -2414,12 +2407,13 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + ansis@4.3.1: + resolution: {integrity: sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==} + engines: {node: '>=14'} argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -2474,6 +2468,10 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-kit@3.0.0-beta.1: + resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==} + engines: {node: '>=20.19.0'} + ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -2534,6 +2532,9 @@ packages: resolution: {integrity: sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w==} engines: {node: ^20.17.0 || >=22.9.0} + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -2541,9 +2542,6 @@ packages: brace-expansion@1.1.13: resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} - brace-expansion@2.0.3: - resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} - brace-expansion@5.0.5: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} @@ -2560,12 +2558,6 @@ packages: bundle-n-require@1.1.2: resolution: {integrity: sha512-bEk2jakVK1ytnZ9R2AAiZEeK/GxPUM8jvcRxHZXifZDMcjkI4EG/GlsJ2YGSVYT9y/p/gA9/0yDY8rCGsSU6Tg==} - bundle-require@5.1.0: - resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - peerDependencies: - esbuild: '>=0.18' - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -2584,6 +2576,10 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + cac@7.0.0: + resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} + engines: {node: '>=20.19.0'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -2621,6 +2617,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} @@ -2652,6 +2652,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -2676,10 +2680,6 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} @@ -2691,6 +2691,11 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concurrently@10.0.3: + resolution: {integrity: sha512-hc3LH4UaKWd/bbyDK/IGVa4RB6PtQ3CUYwtrkzqHn+wIG3Hr5fhpRlk0L/gCa8ZE1L/Ufj50Zho69cI5w8SQBA==} + engines: {node: '>=22'} + hasBin: true + concurrently@9.2.1: resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} engines: {node: '>=18'} @@ -2702,10 +2707,6 @@ packages: confbox@0.2.2: resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - content-disposition@1.1.0: resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} engines: {node: '>=18'} @@ -3032,6 +3033,9 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} @@ -3063,13 +3067,19 @@ packages: dompurify@3.4.3: resolution: {integrity: sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A==} + dts-resolver@3.0.0: + resolution: {integrity: sha512-1T1f+z+4tl9XD+m+0HBgWoL/nm0bOIffyWaUuUSBlFg/86IWvfx+wjNaO/ybU0AJzG9/Mi5hBUgGV6zCmWEN7Q==} + engines: {node: ^22.18.0 || >=24.0.0} + peerDependencies: + oxc-resolver: '>=11.0.0' + peerDependenciesMeta: + oxc-resolver: + optional: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -3080,12 +3090,19 @@ packages: resolution: {integrity: sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==} engines: {node: '>=10.0.0'} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + empathic@2.0.1: + resolution: {integrity: sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==} + engines: {node: '>=14'} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -3519,6 +3536,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -3534,6 +3555,10 @@ packages: get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@5.0.0-beta.5: + resolution: {integrity: sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==} + engines: {node: '>=20.20.0'} + giscus@1.6.0: resolution: {integrity: sha512-Zrsi8r4t1LVW950keaWcsURuZUQwUaMKjvJgTCY125vkW6OiEBkatE7ScJDbpqKHdZwb///7FVC21SE3iFK3PQ==} @@ -3548,11 +3573,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@10.5.0: - resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - glob@13.0.6: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} @@ -3674,6 +3694,9 @@ packages: resolution: {integrity: sha512-7fvVPbB92zNRsQke+uiRGwtTuef0tB2Dg4hWxYfFNvkQhIltWoyi0ONReM5LWA+jJWS3nfT5lTq+qbsIpX0IQw==} engines: {node: '>=16.9.0'} + hookable@6.1.1: + resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} + html-encoding-sniffer@6.0.0: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -3733,6 +3756,10 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + import-without-cache@0.4.0: + resolution: {integrity: sha512-NkJQA7oZ4YHQhd2+H3BoRFKF3d/XNsiKpHZCQEMH9pDX27hQQLsTyOocyRgaIVtf8gHX3Nt3LPkR4e5EdtPAGQ==} + engines: {node: ^22.18.0 || >=24.0.0} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -3924,9 +3951,6 @@ packages: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - javascript-stringify@2.1.0: resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} @@ -3937,10 +3961,6 @@ packages: jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} - joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4243,16 +4263,9 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} - linebreak@1.1.0: resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - lit-element@4.2.2: resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==} @@ -4262,10 +4275,6 @@ packages: lit@3.3.2: resolution: {integrity: sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==} - load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -4276,9 +4285,6 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - lodash.truncate@4.4.2: resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} @@ -4295,9 +4301,6 @@ packages: lowlight@1.20.0: resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.4: resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} engines: {node: 20 || >=22} @@ -4541,10 +4544,6 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -4596,9 +4595,6 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -4751,9 +4747,6 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} @@ -4804,10 +4797,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -4835,10 +4824,6 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} - pkce-challenge@5.0.1: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} @@ -4875,24 +4860,6 @@ packages: peerDependencies: postcss: 8.5.14 - postcss-load-config@6.0.1: - resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} - engines: {node: '>= 18'} - peerDependencies: - jiti: '>=1.21.0' - postcss: 8.5.14 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - jiti: - optional: true - postcss: - optional: true - tsx: - optional: true - yaml: - optional: true - postcss-minify-selectors@7.0.5: resolution: {integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} @@ -4934,8 +4901,8 @@ packages: engines: {node: '>=14'} hasBin: true - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.4: + resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} engines: {node: '>=14'} hasBin: true @@ -4969,6 +4936,9 @@ packages: resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} engines: {node: '>=0.6'} + quansync@1.0.0: + resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -4985,10 +4955,10 @@ packages: peerDependencies: react: ^19.2.5 - react-dom@19.3.0-canary-a757cb76-20251002: - resolution: {integrity: sha512-UvMoAElWcrEe1keKAMZqJ2Rw4wQZah8GFQHvqCLsBd+50LR22sme5hkjiyUO1dnoSVfAvEncARgDfJVEJ1miKA==} + react-dom@19.2.7: + resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} peerDependencies: - react: 19.3.0-canary-a757cb76-20251002 + react: ^19.2.7 react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -5047,8 +5017,8 @@ packages: resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} - react@19.3.0-canary-a757cb76-20251002: - resolution: {integrity: sha512-sbMInOneG99tvHhQShNxQ16JT06vAPT3VIL/ez3O2lFLPOqfjLaS9Ka7mOvu6A80i+R01PIVT4tyluhu71WUtg==} + react@19.2.7: + resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} engines: {node: '>=0.10.0'} read-cmd-shim@6.0.0: @@ -5141,10 +5111,6 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -5167,14 +5133,33 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rolldown-plugin-dts@0.25.2: + resolution: {integrity: sha512-nMhN/R+vmR8GM45ZW1FWMSjRTSDDn/6w4GTf8RNrEFCBdl8B1kySWrU1ixPtbwzXoRlcO+R/S88VgXuJQwfdDg==} + engines: {node: ^22.18.0 || >=24.0.0} + peerDependencies: + '@ts-macro/tsc': ^0.3.6 + '@typescript/native-preview': '>=7.0.0-dev.20260325.1' + rolldown: ^1.0.0 + typescript: ^5.0.0 || ^6.0.0 + vue-tsc: ~3.2.0 + peerDependenciesMeta: + '@ts-macro/tsc': + optional: true + '@typescript/native-preview': + optional: true + typescript: + optional: true + vue-tsc: + optional: true + rolldown@1.0.2: resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.60.4: - resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + rolldown@1.1.1: + resolution: {integrity: sha512-IN750c0p+s3jqJIsFLRZrQazmbAB1kkQDTtQjSt/gbS2ywLhlv4R5Shazer0FZKmuo/BsO3/w2UoYnUjuOZqHg==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true roughjs@4.6.6: @@ -5219,9 +5204,6 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - scheduler@0.28.0-canary-a757cb76-20251002: - resolution: {integrity: sha512-H6/e/ybFu7/U5c+e1QcBtB/8ZDXHLpOX67KU3lXt/PIzWLo6oZzO3pwuqviUlSFHKVeEriSO8jJuB4L0hH7wrQ==} - section-matter@1.0.0: resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} engines: {node: '>=4'} @@ -5235,6 +5217,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.4: + resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} + engines: {node: '>=10'} + hasBin: true + send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} @@ -5277,6 +5264,10 @@ packages: resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} + shell-quote@1.8.4: + resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==} + engines: {node: '>= 0.4'} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -5315,11 +5306,6 @@ packages: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - deprecated: The work that was done in this beta branch won't be included in future versions - space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -5350,9 +5336,9 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} string.prototype.codepointat@0.2.1: resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==} @@ -5387,8 +5373,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-bom-string@1.0.0: @@ -5429,16 +5415,15 @@ packages: stylis@4.3.6: resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - supabase@2.88.1: resolution: {integrity: sha512-kGtKVV4Hze5ehJKHIb30+Hw6jq7gX7rm3aQ1olVCk6u4rXftKPbK6nW8LttPmvYYkLSLBDDni5rowOpee7aMyA==} engines: {npm: '>=8'} hasBin: true + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -5474,13 +5459,6 @@ packages: resolution: {integrity: sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==} engines: {node: 20 || >=22} - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - third-party-capital@1.0.20: resolution: {integrity: sha512-oB7yIimd8SuGptespDAZnNkzIz+NWaJCu2RMsbs4Wmp9zSDUM8Nhi3s2OOcqYuv3mN4hitXc8DVx+LyUmbUDiA==} @@ -5493,21 +5471,22 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} @@ -5535,9 +5514,6 @@ packages: resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} engines: {node: '>=16'} - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - tr46@6.0.0: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} @@ -5572,9 +5548,6 @@ packages: jsdom: optional: true - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-morph@28.0.0: resolution: {integrity: sha512-Wp3tnZ2bzwxyTZMtgWVzXDfm7lB1Drz+y9DmmYH/L702PQhPyVrp3pkou3yIz4qjS14GY9kcpmLiOOMvl8oG1g==} @@ -5594,35 +5567,50 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsup@8.4.0: - resolution: {integrity: sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ==} - engines: {node: '>=18'} + tsdown@0.22.2: + resolution: {integrity: sha512-VX9gsyKXsTnBZjnIM4jsHl9aRv+GfgkE/k1hQslilaBfZMlaw3JuGR+6yhiU0QxWBtOCDnTjwOSoXzgB7Rr50g==} + engines: {node: ^22.18.0 || >=24.0.0} hasBin: true peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: 8.5.14 - typescript: '>=4.5.0' + '@arethetypeswrong/core': ^0.18.1 + '@tsdown/css': 0.22.2 + '@tsdown/exe': 0.22.2 + '@vitejs/devtools': '*' + publint: ^0.3.8 + tsx: '*' + typescript: ^5.0.0 || ^6.0.0 + unplugin-unused: ^0.5.0 + unrun: '*' peerDependenciesMeta: - '@microsoft/api-extractor': + '@arethetypeswrong/core': + optional: true + '@tsdown/css': + optional: true + '@tsdown/exe': optional: true - '@swc/core': + '@vitejs/devtools': + optional: true + publint: optional: true - postcss: + tsx: optional: true typescript: optional: true + unplugin-unused: + optional: true + unrun: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} tsx@4.22.3: resolution: {integrity: sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==} engines: {node: '>=18.0.0'} hasBin: true - turbo@2.9.5: - resolution: {integrity: sha512-JXNkRe6H6MjSlk5UQRTjyoKX5YN2zlc2632xcSlSFBao5yvbMWTpv9SNolOZlZmUlcDOHuszPLItbKrvcXnnZA==} + turbo@2.9.18: + resolution: {integrity: sha512-bwabv6PupzeavybzEoArBAkwq5fnzwf8OFnRtpHwnviFWuwJPFxtyH+aVp36TmIqK3aYYgtTJ3J0m2ysxxSzQg==} hasBin: true type-check@0.4.0: @@ -5664,18 +5652,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} - engines: {node: '>=14.17'} - hasBin: true - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + typescript@6.0.2: + resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} engines: {node: '>=14.17'} hasBin: true - typescript@6.0.2: - resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true @@ -5686,6 +5669,9 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + unconfig-core@7.5.0: + resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} + undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} @@ -5873,9 +5859,6 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - webidl-conversions@8.0.0: resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} engines: {node: '>=20'} @@ -5903,9 +5886,6 @@ packages: resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -5952,9 +5932,9 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -5997,10 +5977,18 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -6116,6 +6104,15 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 + '@babel/generator@8.0.0-rc.6': + dependencies: + '@babel/parser': 8.0.0-rc.6 + '@babel/types': 8.0.0-rc.6 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@types/jsesc': 2.5.1 + jsesc: 3.1.0 + '@babel/helper-compilation-targets@7.28.6': dependencies: '@babel/compat-data': 7.28.6 @@ -6146,8 +6143,12 @@ snapshots: '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@8.0.0-rc.6': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@8.0.0-rc.6': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.28.6': @@ -6159,6 +6160,10 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@babel/parser@8.0.0-rc.6': + dependencies: + '@babel/types': 8.0.0-rc.6 + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -6194,6 +6199,11 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@8.0.0-rc.6': + dependencies: + '@babel/helper-string-parser': 8.0.0-rc.6 + '@babel/helper-validator-identifier': 8.0.0-rc.6 + '@bcoe/v8-coverage@1.0.2': {} '@braintree/sanitize-url@7.1.1': {} @@ -6277,11 +6287,22 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/core@1.11.0': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.11.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 @@ -6292,6 +6313,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.25.12': optional: true @@ -6500,11 +6526,11 @@ snapshots: '@exodus/bytes@1.9.0': {} - '@giscus/react@3.1.0(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002)': + '@giscus/react@3.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: giscus: 1.6.0 - react: 19.3.0-canary-a757cb76-20251002 - react-dom: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) '@hono/node-server@1.19.14(hono@4.12.22)': dependencies: @@ -6654,15 +6680,6 @@ snapshots: optionalDependencies: '@types/node': 25.9.1 - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.3 @@ -6732,11 +6749,11 @@ snapshots: - acorn - supports-color - '@mdx-js/react@3.1.1(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002)': + '@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 19.2.15 - react: 19.3.0-canary-a757cb76-20251002 + '@types/react': 19.2.17 + react: 19.2.7 '@mermaid-js/parser@1.1.1': dependencies: @@ -6780,18 +6797,25 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)': + dependencies: + '@emnapi/core': 1.11.0 + '@emnapi/runtime': 1.11.0 + '@tybys/wasm-util': 0.10.2 + optional: true + '@next/env@16.2.6': {} '@next/eslint-plugin-next@16.2.6': dependencies: fast-glob: 3.3.1 - '@next/mdx@16.2.6(@mdx-js/loader@3.1.1(acorn@8.16.0))(@mdx-js/react@3.1.1(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002))': + '@next/mdx@16.2.6(@mdx-js/loader@3.1.1(acorn@8.16.0))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))': dependencies: source-map: 0.7.4 optionalDependencies: '@mdx-js/loader': 3.1.1(acorn@8.16.0) - '@mdx-js/react': 3.1.1(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002) + '@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7) '@next/swc-darwin-arm64@16.2.6': optional: true @@ -6817,10 +6841,10 @@ snapshots: '@next/swc-win32-x64-msvc@16.2.6': optional: true - '@next/third-parties@16.2.6(next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002)': + '@next/third-parties@16.2.6(next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)': dependencies: - next: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) - react: 19.3.0-canary-a757cb76-20251002 + next: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 third-party-capital: 1.0.20 '@nodelib/fs.scandir@2.1.5': @@ -6848,6 +6872,8 @@ snapshots: '@oxc-project/types@0.132.0': {} + '@oxc-project/types@0.135.0': {} + '@pandacss/config@1.11.1': dependencies: '@pandacss/logger': 1.11.1 @@ -6880,14 +6906,14 @@ snapshots: postcss-selector-parser: 7.1.1 ts-pattern: 5.9.0 - '@pandacss/dev@1.11.1(jsdom@27.4.0)(typescript@5.8.3)': + '@pandacss/dev@1.11.1(jsdom@27.4.0)(typescript@6.0.3)': dependencies: '@clack/prompts': 0.11.0 '@pandacss/config': 1.11.1 '@pandacss/logger': 1.11.1 - '@pandacss/mcp': 1.11.1(jsdom@27.4.0)(typescript@5.8.3) - '@pandacss/node': 1.11.1(jsdom@27.4.0)(typescript@5.8.3) - '@pandacss/postcss': 1.11.1(jsdom@27.4.0)(typescript@5.8.3) + '@pandacss/mcp': 1.11.1(jsdom@27.4.0)(typescript@6.0.3) + '@pandacss/node': 1.11.1(jsdom@27.4.0)(typescript@6.0.3) + '@pandacss/postcss': 1.11.1(jsdom@27.4.0)(typescript@6.0.3) '@pandacss/preset-base': 1.11.1 '@pandacss/preset-panda': 1.11.1 '@pandacss/shared': 1.11.1 @@ -6900,14 +6926,14 @@ snapshots: - supports-color - typescript - '@pandacss/dev@1.11.1(jsdom@29.1.1)(typescript@5.8.3)': + '@pandacss/dev@1.11.1(jsdom@29.1.1)(typescript@6.0.3)': dependencies: '@clack/prompts': 0.11.0 '@pandacss/config': 1.11.1 '@pandacss/logger': 1.11.1 - '@pandacss/mcp': 1.11.1(jsdom@29.1.1)(typescript@5.8.3) - '@pandacss/node': 1.11.1(jsdom@29.1.1)(typescript@5.8.3) - '@pandacss/postcss': 1.11.1(jsdom@29.1.1)(typescript@5.8.3) + '@pandacss/mcp': 1.11.1(jsdom@29.1.1)(typescript@6.0.3) + '@pandacss/node': 1.11.1(jsdom@29.1.1)(typescript@6.0.3) + '@pandacss/postcss': 1.11.1(jsdom@29.1.1)(typescript@6.0.3) '@pandacss/preset-base': 1.11.1 '@pandacss/preset-panda': 1.11.1 '@pandacss/shared': 1.11.1 @@ -6920,14 +6946,14 @@ snapshots: - supports-color - typescript - '@pandacss/dev@1.11.1(typescript@5.8.3)': + '@pandacss/dev@1.11.1(typescript@6.0.3)': dependencies: '@clack/prompts': 0.11.0 '@pandacss/config': 1.11.1 '@pandacss/logger': 1.11.1 - '@pandacss/mcp': 1.11.1(typescript@5.8.3) - '@pandacss/node': 1.11.1(typescript@5.8.3) - '@pandacss/postcss': 1.11.1(typescript@5.8.3) + '@pandacss/mcp': 1.11.1(typescript@6.0.3) + '@pandacss/node': 1.11.1(typescript@6.0.3) + '@pandacss/postcss': 1.11.1(typescript@6.0.3) '@pandacss/preset-base': 1.11.1 '@pandacss/preset-panda': 1.11.1 '@pandacss/shared': 1.11.1 @@ -6940,19 +6966,19 @@ snapshots: - supports-color - typescript - '@pandacss/extractor@1.11.1(jsdom@27.4.0)(typescript@5.8.3)': + '@pandacss/extractor@1.11.1(jsdom@27.4.0)(typescript@6.0.3)': dependencies: '@pandacss/shared': 1.11.1 - ts-evaluator: 1.2.0(jsdom@27.4.0)(typescript@5.8.3) + ts-evaluator: 1.2.0(jsdom@27.4.0)(typescript@6.0.3) ts-morph: 28.0.0 transitivePeerDependencies: - jsdom - typescript - '@pandacss/extractor@1.11.1(jsdom@29.1.1)(typescript@5.8.3)': + '@pandacss/extractor@1.11.1(jsdom@29.1.1)(typescript@6.0.3)': dependencies: '@pandacss/shared': 1.11.1 - ts-evaluator: 1.2.0(jsdom@29.1.1)(typescript@5.8.3) + ts-evaluator: 1.2.0(jsdom@29.1.1)(typescript@6.0.3) ts-morph: 28.0.0 transitivePeerDependencies: - jsdom @@ -6979,12 +7005,12 @@ snapshots: '@pandacss/types': 1.11.1 kleur: 4.1.5 - '@pandacss/mcp@1.11.1(jsdom@27.4.0)(typescript@5.8.3)': + '@pandacss/mcp@1.11.1(jsdom@27.4.0)(typescript@6.0.3)': dependencies: '@clack/prompts': 0.11.0 '@modelcontextprotocol/sdk': 1.29.0(zod@4.2.1) '@pandacss/logger': 1.11.1 - '@pandacss/node': 1.11.1(jsdom@27.4.0)(typescript@5.8.3) + '@pandacss/node': 1.11.1(jsdom@27.4.0)(typescript@6.0.3) '@pandacss/token-dictionary': 1.11.1 '@pandacss/types': 1.11.1 zod: 4.2.1 @@ -6994,12 +7020,12 @@ snapshots: - supports-color - typescript - '@pandacss/mcp@1.11.1(jsdom@29.1.1)(typescript@5.8.3)': + '@pandacss/mcp@1.11.1(jsdom@29.1.1)(typescript@6.0.3)': dependencies: '@clack/prompts': 0.11.0 '@modelcontextprotocol/sdk': 1.29.0(zod@4.2.1) '@pandacss/logger': 1.11.1 - '@pandacss/node': 1.11.1(jsdom@29.1.1)(typescript@5.8.3) + '@pandacss/node': 1.11.1(jsdom@29.1.1)(typescript@6.0.3) '@pandacss/token-dictionary': 1.11.1 '@pandacss/types': 1.11.1 zod: 4.2.1 @@ -7009,12 +7035,12 @@ snapshots: - supports-color - typescript - '@pandacss/mcp@1.11.1(typescript@5.8.3)': + '@pandacss/mcp@1.11.1(typescript@6.0.3)': dependencies: '@clack/prompts': 0.11.0 '@modelcontextprotocol/sdk': 1.29.0(zod@4.2.1) '@pandacss/logger': 1.11.1 - '@pandacss/node': 1.11.1(typescript@5.8.3) + '@pandacss/node': 1.11.1(typescript@6.0.3) '@pandacss/token-dictionary': 1.11.1 '@pandacss/types': 1.11.1 zod: 4.2.1 @@ -7024,13 +7050,13 @@ snapshots: - supports-color - typescript - '@pandacss/node@1.11.1(jsdom@27.4.0)(typescript@5.8.3)': + '@pandacss/node@1.11.1(jsdom@27.4.0)(typescript@6.0.3)': dependencies: '@pandacss/config': 1.11.1 '@pandacss/core': 1.11.1 '@pandacss/generator': 1.11.1 '@pandacss/logger': 1.11.1 - '@pandacss/parser': 1.11.1(jsdom@27.4.0)(typescript@5.8.3) + '@pandacss/parser': 1.11.1(jsdom@27.4.0)(typescript@6.0.3) '@pandacss/plugin-lightningcss': 1.11.1 '@pandacss/plugin-svelte': 1.11.1 '@pandacss/plugin-vue': 1.11.1 @@ -7062,13 +7088,13 @@ snapshots: - jsdom - typescript - '@pandacss/node@1.11.1(jsdom@29.1.1)(typescript@5.8.3)': + '@pandacss/node@1.11.1(jsdom@29.1.1)(typescript@6.0.3)': dependencies: '@pandacss/config': 1.11.1 '@pandacss/core': 1.11.1 '@pandacss/generator': 1.11.1 '@pandacss/logger': 1.11.1 - '@pandacss/parser': 1.11.1(jsdom@29.1.1)(typescript@5.8.3) + '@pandacss/parser': 1.11.1(jsdom@29.1.1)(typescript@6.0.3) '@pandacss/plugin-lightningcss': 1.11.1 '@pandacss/plugin-svelte': 1.11.1 '@pandacss/plugin-vue': 1.11.1 @@ -7100,13 +7126,13 @@ snapshots: - jsdom - typescript - '@pandacss/node@1.11.1(typescript@5.8.3)': + '@pandacss/node@1.11.1(typescript@6.0.3)': dependencies: '@pandacss/config': 1.11.1 '@pandacss/core': 1.11.1 '@pandacss/generator': 1.11.1 '@pandacss/logger': 1.11.1 - '@pandacss/parser': 1.11.1(typescript@5.8.3) + '@pandacss/parser': 1.11.1(typescript@6.0.3) '@pandacss/plugin-lightningcss': 1.11.1 '@pandacss/plugin-svelte': 1.11.1 '@pandacss/plugin-vue': 1.11.1 @@ -7138,11 +7164,11 @@ snapshots: - jsdom - typescript - '@pandacss/parser@1.11.1(jsdom@27.4.0)(typescript@5.8.3)': + '@pandacss/parser@1.11.1(jsdom@27.4.0)(typescript@6.0.3)': dependencies: '@pandacss/config': 1.11.1 '@pandacss/core': 1.11.1 - '@pandacss/extractor': 1.11.1(jsdom@27.4.0)(typescript@5.8.3) + '@pandacss/extractor': 1.11.1(jsdom@27.4.0)(typescript@6.0.3) '@pandacss/logger': 1.11.1 '@pandacss/shared': 1.11.1 '@pandacss/types': 1.11.1 @@ -7152,11 +7178,11 @@ snapshots: - jsdom - typescript - '@pandacss/parser@1.11.1(jsdom@29.1.1)(typescript@5.8.3)': + '@pandacss/parser@1.11.1(jsdom@29.1.1)(typescript@6.0.3)': dependencies: '@pandacss/config': 1.11.1 '@pandacss/core': 1.11.1 - '@pandacss/extractor': 1.11.1(jsdom@29.1.1)(typescript@5.8.3) + '@pandacss/extractor': 1.11.1(jsdom@29.1.1)(typescript@6.0.3) '@pandacss/logger': 1.11.1 '@pandacss/shared': 1.11.1 '@pandacss/types': 1.11.1 @@ -7166,11 +7192,11 @@ snapshots: - jsdom - typescript - '@pandacss/parser@1.11.1(typescript@5.8.3)': + '@pandacss/parser@1.11.1(typescript@6.0.3)': dependencies: '@pandacss/config': 1.11.1 '@pandacss/core': 1.11.1 - '@pandacss/extractor': 1.11.1(jsdom@29.1.1)(typescript@5.8.3) + '@pandacss/extractor': 1.11.1(jsdom@29.1.1)(typescript@6.0.3) '@pandacss/logger': 1.11.1 '@pandacss/shared': 1.11.1 '@pandacss/types': 1.11.1 @@ -7198,25 +7224,25 @@ snapshots: '@vue/compiler-sfc': 3.5.25 magic-string: 0.30.21 - '@pandacss/postcss@1.11.1(jsdom@27.4.0)(typescript@5.8.3)': + '@pandacss/postcss@1.11.1(jsdom@27.4.0)(typescript@6.0.3)': dependencies: - '@pandacss/node': 1.11.1(jsdom@27.4.0)(typescript@5.8.3) + '@pandacss/node': 1.11.1(jsdom@27.4.0)(typescript@6.0.3) postcss: 8.5.14 transitivePeerDependencies: - jsdom - typescript - '@pandacss/postcss@1.11.1(jsdom@29.1.1)(typescript@5.8.3)': + '@pandacss/postcss@1.11.1(jsdom@29.1.1)(typescript@6.0.3)': dependencies: - '@pandacss/node': 1.11.1(jsdom@29.1.1)(typescript@5.8.3) + '@pandacss/node': 1.11.1(jsdom@29.1.1)(typescript@6.0.3) postcss: 8.5.14 transitivePeerDependencies: - jsdom - typescript - '@pandacss/postcss@1.11.1(typescript@5.8.3)': + '@pandacss/postcss@1.11.1(typescript@6.0.3)': dependencies: - '@pandacss/node': 1.11.1(typescript@5.8.3) + '@pandacss/node': 1.11.1(typescript@6.0.3) postcss: 8.5.14 transitivePeerDependencies: - jsdom @@ -7252,10 +7278,11 @@ snapshots: '@pandacss/types@1.11.1': {} - '@pkgjs/parseargs@0.11.0': - optional: true + '@quansync/fs@1.0.0': + dependencies: + quansync: 1.0.0 - '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002)(redux@5.0.1))(react@19.3.0-canary-a757cb76-20251002)': + '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7)': dependencies: '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 @@ -7264,8 +7291,8 @@ snapshots: redux-thunk: 3.1.0(redux@5.0.1) reselect: 5.1.1 optionalDependencies: - react: 19.3.0-canary-a757cb76-20251002 - react-redux: 9.2.0(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002)(redux@5.0.1) + react: 19.2.7 + react-redux: 9.2.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1) '@resvg/resvg-js-android-arm-eabi@2.6.2': optional: true @@ -7321,130 +7348,104 @@ snapshots: '@rolldown/binding-android-arm64@1.0.2': optional: true - '@rolldown/binding-darwin-arm64@1.0.2': - optional: true - - '@rolldown/binding-darwin-x64@1.0.2': - optional: true - - '@rolldown/binding-freebsd-x64@1.0.2': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.0.2': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.0.2': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.0.2': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.0.2': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.0.2': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.0.2': + '@rolldown/binding-android-arm64@1.1.1': optional: true - '@rolldown/binding-linux-x64-musl@1.0.2': + '@rolldown/binding-darwin-arm64@1.0.2': optional: true - '@rolldown/binding-openharmony-arm64@1.0.2': + '@rolldown/binding-darwin-arm64@1.1.1': optional: true - '@rolldown/binding-wasm32-wasi@1.0.2': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@rolldown/binding-darwin-x64@1.0.2': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.2': + '@rolldown/binding-darwin-x64@1.1.1': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.2': + '@rolldown/binding-freebsd-x64@1.0.2': optional: true - '@rolldown/pluginutils@1.0.0-rc.3': {} - - '@rolldown/pluginutils@1.0.1': {} - - '@rollup/rollup-android-arm-eabi@4.60.4': + '@rolldown/binding-freebsd-x64@1.1.1': optional: true - '@rollup/rollup-android-arm64@4.60.4': + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': optional: true - '@rollup/rollup-darwin-arm64@4.60.4': + '@rolldown/binding-linux-arm-gnueabihf@1.1.1': optional: true - '@rollup/rollup-darwin-x64@4.60.4': + '@rolldown/binding-linux-arm64-gnu@1.0.2': optional: true - '@rollup/rollup-freebsd-arm64@4.60.4': + '@rolldown/binding-linux-arm64-gnu@1.1.1': optional: true - '@rollup/rollup-freebsd-x64@4.60.4': + '@rolldown/binding-linux-arm64-musl@1.0.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + '@rolldown/binding-linux-arm64-musl@1.1.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.4': + '@rolldown/binding-linux-ppc64-gnu@1.0.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.4': + '@rolldown/binding-linux-ppc64-gnu@1.1.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.4': + '@rolldown/binding-linux-s390x-gnu@1.0.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.4': + '@rolldown/binding-linux-s390x-gnu@1.1.1': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.4': + '@rolldown/binding-linux-x64-gnu@1.0.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.4': + '@rolldown/binding-linux-x64-gnu@1.1.1': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.4': + '@rolldown/binding-linux-x64-musl@1.0.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.4': + '@rolldown/binding-linux-x64-musl@1.1.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.4': + '@rolldown/binding-openharmony-arm64@1.0.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.4': + '@rolldown/binding-openharmony-arm64@1.1.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.4': + '@rolldown/binding-wasm32-wasi@1.0.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rollup/rollup-linux-x64-musl@4.60.4': + '@rolldown/binding-wasm32-wasi@1.1.1': + dependencies: + '@emnapi/core': 1.11.0 + '@emnapi/runtime': 1.11.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0) optional: true - '@rollup/rollup-openbsd-x64@4.60.4': + '@rolldown/binding-win32-arm64-msvc@1.0.2': optional: true - '@rollup/rollup-openharmony-arm64@4.60.4': + '@rolldown/binding-win32-arm64-msvc@1.1.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.4': + '@rolldown/binding-win32-x64-msvc@1.0.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.4': + '@rolldown/binding-win32-x64-msvc@1.1.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.4': - optional: true + '@rolldown/pluginutils@1.0.0-rc.3': {} - '@rollup/rollup-win32-x64-msvc@4.60.4': - optional: true + '@rolldown/pluginutils@1.0.1': {} '@rtsao/scc@1.1.0': {} @@ -7515,10 +7516,10 @@ snapshots: '@tanstack/query-core@5.100.14': {} - '@tanstack/react-query@5.100.14(react@19.3.0-canary-a757cb76-20251002)': + '@tanstack/react-query@5.100.14(react@19.2.7)': dependencies: '@tanstack/query-core': 5.100.14 - react: 19.3.0-canary-a757cb76-20251002 + react: 19.2.7 '@testing-library/dom@10.4.1': dependencies: @@ -7540,15 +7541,15 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.0(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@babel/runtime': 7.29.2 '@testing-library/dom': 10.4.1 - react: 19.3.0-canary-a757cb76-20251002 - react-dom: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.0(@types/react@19.2.15) + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': dependencies: @@ -7560,22 +7561,22 @@ snapshots: path-browserify: 1.0.1 tinyglobby: 0.2.16 - '@turbo/darwin-64@2.9.5': + '@turbo/darwin-64@2.9.18': optional: true - '@turbo/darwin-arm64@2.9.5': + '@turbo/darwin-arm64@2.9.18': optional: true - '@turbo/linux-64@2.9.5': + '@turbo/linux-64@2.9.18': optional: true - '@turbo/linux-arm64@2.9.5': + '@turbo/linux-arm64@2.9.18': optional: true - '@turbo/windows-64@2.9.5': + '@turbo/windows-64@2.9.18': optional: true - '@turbo/windows-arm64@2.9.5': + '@turbo/windows-arm64@2.9.18': optional: true '@tybys/wasm-util@0.10.2': @@ -7750,6 +7751,8 @@ snapshots: '@types/istanbul-lib-coverage@2.0.6': {} + '@types/jsesc@2.5.1': {} + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -7772,9 +7775,9 @@ snapshots: '@types/prismjs@1.26.5': {} - '@types/react-dom@19.2.0(@types/react@19.2.15)': + '@types/react-dom@19.2.3(@types/react@19.2.17)': dependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.17 '@types/react-syntax-highlighter@15.5.13': dependencies: @@ -7784,6 +7787,10 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/react@19.2.17': + dependencies: + csstype: 3.2.3 + '@types/statuses@2.0.6': {} '@types/trusted-types@2.0.7': {} @@ -7798,40 +7805,40 @@ snapshots: dependencies: '@types/node': 25.9.1 - '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3))(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/type-utils': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/type-utils': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) + '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.58.1 eslint: 9.39.4(jiti@2.4.2) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.58.1 '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.58.1 debug: 4.4.3 eslint: 9.39.4(jiti@2.4.2) - typescript: 5.8.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.1(typescript@5.8.3)': + '@typescript-eslint/project-service@8.58.1(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.3) '@typescript-eslint/types': 8.58.1 debug: 4.4.3 - typescript: 5.8.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -7840,47 +7847,47 @@ snapshots: '@typescript-eslint/types': 8.58.1 '@typescript-eslint/visitor-keys': 8.58.1 - '@typescript-eslint/tsconfig-utils@8.58.1(typescript@5.8.3)': + '@typescript-eslint/tsconfig-utils@8.58.1(typescript@6.0.3)': dependencies: - typescript: 5.8.3 + typescript: 6.0.3 - '@typescript-eslint/type-utils@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.8.3) - '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.3) + '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) debug: 4.4.3 eslint: 9.39.4(jiti@2.4.2) - ts-api-utils: 2.5.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@8.58.1': {} - '@typescript-eslint/typescript-estree@8.58.1(typescript@5.8.3)': + '@typescript-eslint/typescript-estree@8.58.1(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.58.1(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@5.8.3) + '@typescript-eslint/project-service': 8.58.1(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.3) '@typescript-eslint/types': 8.58.1 '@typescript-eslint/visitor-keys': 8.58.1 debug: 4.4.3 minimatch: 10.2.5 semver: 7.7.4 tinyglobby: 0.2.16 - ts-api-utils: 2.5.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.58.1 '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.3) eslint: 9.39.4(jiti@2.4.2) - typescript: 5.8.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -7917,13 +7924,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.4(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3))': + '@vitest/mocker@4.1.4(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3))': dependencies: '@vitest/spy': 4.1.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.13.2(@types/node@25.9.1)(typescript@5.8.3) + msw: 2.13.2(@types/node@25.9.1)(typescript@6.0.3) vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3) '@vitest/pretty-format@4.1.4': @@ -8023,7 +8030,7 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.1.0: {} + ansi-regex@6.2.2: {} ansi-styles@4.3.0: dependencies: @@ -8031,9 +8038,9 @@ snapshots: ansi-styles@5.2.0: {} - ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} - any-promise@1.3.0: {} + ansis@4.3.1: {} argparse@1.0.10: dependencies: @@ -8125,6 +8132,12 @@ snapshots: assertion-error@2.0.1: {} + ast-kit@3.0.0-beta.1: + dependencies: + '@babel/parser': 8.0.0-rc.6 + estree-walker: 3.0.3 + pathe: 2.0.3 + ast-types-flow@0.0.8: {} astral-regex@2.0.0: {} @@ -8169,6 +8182,8 @@ snapshots: read-cmd-shim: 6.0.0 write-file-atomic: 7.0.0 + birpc@4.0.0: {} + body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -8188,10 +8203,6 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.3: - dependencies: - balanced-match: 1.0.2 - brace-expansion@5.0.5: dependencies: balanced-match: 4.0.4 @@ -8213,11 +8224,6 @@ snapshots: esbuild: 0.25.12 node-eval: 2.0.0 - bundle-require@5.1.0(esbuild@0.25.12): - dependencies: - esbuild: 0.25.12 - load-tsconfig: 0.2.5 - bytes@3.1.2: {} c8@11.0.0: @@ -8236,6 +8242,8 @@ snapshots: cac@6.7.14: {} + cac@7.0.0: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -8273,6 +8281,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.6.2: {} + character-entities-html4@2.1.0: {} character-entities-legacy@3.0.0: {} @@ -8297,6 +8307,12 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + clsx@2.1.1: {} cmd-shim@8.0.0: {} @@ -8313,14 +8329,21 @@ snapshots: comma-separated-tokens@2.0.3: {} - commander@4.1.1: {} - commander@7.2.0: {} commander@8.3.0: {} concat-map@0.0.1: {} + concurrently@10.0.3: + dependencies: + chalk: 5.6.2 + rxjs: 7.8.2 + shell-quote: 1.8.4 + supports-color: 10.2.2 + tree-kill: 1.2.2 + yargs: 18.0.0 + concurrently@9.2.1: dependencies: chalk: 4.1.2 @@ -8334,8 +8357,6 @@ snapshots: confbox@0.2.2: {} - consola@3.4.2: {} - content-disposition@1.1.0: {} content-type@1.0.5: {} @@ -8668,6 +8689,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.7: {} + delaunator@5.0.1: dependencies: robust-predicates: 3.0.2 @@ -8694,24 +8717,28 @@ snapshots: optionalDependencies: '@types/trusted-types': 2.0.7 + dts-resolver@3.0.0: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 es-errors: 1.3.0 gopd: 1.2.0 - eastasianwidth@0.2.0: {} - ee-first@1.1.1: {} electron-to-chromium@1.5.277: {} emoji-regex-xs@2.0.1: {} + emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} + empathic@2.0.1: {} + encodeurl@2.0.0: {} enhanced-resolve@5.18.1: @@ -8966,7 +8993,7 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-next@16.2.6(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3): + eslint-config-next@16.2.6(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3): dependencies: '@next/eslint-plugin-next': 16.2.6 eslint: 9.39.4(jiti@2.4.2) @@ -8977,9 +9004,9 @@ snapshots: eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.4.2)) eslint-plugin-react-hooks: 7.0.1(eslint@9.39.4(jiti@2.4.2)) globals: 16.4.0 - typescript-eslint: 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) + typescript-eslint: 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) optionalDependencies: - typescript: 5.8.3 + typescript: 6.0.3 transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-webpack @@ -9370,14 +9397,14 @@ snapshots: forwarded@0.2.0: {} - framer-motion@12.38.0(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002): + framer-motion@12.38.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: motion-dom: 12.38.0 motion-utils: 12.36.0 tslib: 2.8.1 optionalDependencies: - react: 19.3.0-canary-a757cb76-20251002 - react-dom: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) fresh@2.0.0: {} @@ -9407,6 +9434,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.6.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -9435,6 +9464,10 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-tsconfig@5.0.0-beta.5: + dependencies: + resolve-pkg-maps: 1.0.0 + giscus@1.6.0: dependencies: lit: 3.3.2 @@ -9449,15 +9482,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@10.5.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.9 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - glob@13.0.6: dependencies: minimatch: 10.2.5 @@ -9632,6 +9656,8 @@ snapshots: hono@4.12.22: {} + hookable@6.1.1: {} + html-encoding-sniffer@6.0.0: dependencies: '@exodus/bytes': 1.15.1 @@ -9696,6 +9722,8 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-without-cache@0.4.0: {} + imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -9878,12 +9906,6 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - javascript-stringify@2.1.0: {} jiti@2.4.2: @@ -9891,8 +9913,6 @@ snapshots: jose@6.2.3: {} - joycon@3.1.1: {} - js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -10159,15 +10179,11 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 - lilconfig@3.1.3: {} - linebreak@1.1.0: dependencies: base64-js: 0.0.8 unicode-trie: 2.0.0 - lines-and-columns@1.2.4: {} - lit-element@4.2.2: dependencies: '@lit-labs/ssr-dom-shim': 1.5.0 @@ -10184,8 +10200,6 @@ snapshots: lit-element: 4.2.2 lit-html: 3.3.2 - load-tsconfig@0.2.5: {} - locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -10194,8 +10208,6 @@ snapshots: lodash.merge@4.6.2: {} - lodash.sortby@4.7.0: {} - lodash.truncate@4.4.2: {} longest-streak@3.1.0: {} @@ -10211,8 +10223,6 @@ snapshots: fault: 1.0.4 highlight.js: 10.7.3 - lru-cache@10.4.3: {} - lru-cache@11.2.4: {} lru-cache@11.5.0: {} @@ -10221,9 +10231,9 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@0.563.0(react@19.3.0-canary-a757cb76-20251002): + lucide-react@0.563.0(react@19.2.7): dependencies: - react: 19.3.0-canary-a757cb76-20251002 + react: 19.2.7 lz-string@1.5.0: {} @@ -10727,10 +10737,6 @@ snapshots: dependencies: brace-expansion: 1.1.13 - minimatch@9.0.9: - dependencies: - brace-expansion: 2.0.3 - minimist@1.2.8: {} minipass@7.1.3: {} @@ -10752,17 +10758,17 @@ snapshots: motion-utils@12.36.0: {} - motion@12.38.0(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002): + motion@12.38.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - framer-motion: 12.38.0(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + framer-motion: 12.38.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tslib: 2.8.1 optionalDependencies: - react: 19.3.0-canary-a757cb76-20251002 - react-dom: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) ms@2.1.3: {} - msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3): + msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3): dependencies: '@inquirer/confirm': 5.1.9(@types/node@25.9.1) '@mswjs/interceptors': 0.41.3 @@ -10783,39 +10789,33 @@ snapshots: until-async: 3.0.2 yargs: 17.7.2 optionalDependencies: - typescript: 5.8.3 + typescript: 6.0.3 transitivePeerDependencies: - '@types/node' mute-stream@2.0.0: {} - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - nanoid@3.3.11: {} natural-compare@1.4.0: {} negotiator@1.0.0: {} - next-router-mock@0.9.13(next@16.2.6(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002): + next-router-mock@0.9.13(next@16.2.6(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7): dependencies: - next: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) - react: 19.3.0-canary-a757cb76-20251002 + next: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 - next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002): + next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: '@next/env': 16.2.6 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.18 caniuse-lite: 1.0.30001765 postcss: 8.5.14 - react: 19.3.0-canary-a757cb76-20251002 - react-dom: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) - styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.3.0-canary-a757cb76-20251002) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.7) optionalDependencies: '@next/swc-darwin-arm64': 16.2.6 '@next/swc-darwin-x64': 16.2.6 @@ -10847,13 +10847,13 @@ snapshots: npm-normalize-package-bin@5.0.0: {} - nuqs@2.8.9(next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002))(react-router@7.15.1(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002): + nuqs@2.8.9(next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7): dependencies: '@standard-schema/spec': 1.0.0 - react: 19.3.0-canary-a757cb76-20251002 + react: 19.2.7 optionalDependencies: - next: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) - react-router: 7.15.1(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002) + next: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react-router: 7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) object-assign@4.1.1: {} @@ -10940,8 +10940,6 @@ snapshots: dependencies: p-limit: 3.1.0 - package-json-from-dist@1.0.1: {} - package-manager-detector@1.6.0: {} pako@0.2.9: {} @@ -10991,11 +10989,6 @@ snapshots: path-parse@1.0.7: {} - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.3 - path-scurry@2.0.2: dependencies: lru-cache: 11.5.0 @@ -11015,8 +11008,6 @@ snapshots: picomatch@4.0.4: {} - pirates@4.0.6: {} - pkce-challenge@5.0.1: {} pkg-types@1.3.1: @@ -11050,14 +11041,6 @@ snapshots: dependencies: postcss: 8.5.14 - postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.14)(tsx@4.22.3): - dependencies: - lilconfig: 3.1.3 - optionalDependencies: - jiti: 2.4.2 - postcss: 8.5.14 - tsx: 4.22.3 - postcss-minify-selectors@7.0.5(postcss@8.5.14): dependencies: cssesc: 3.0.0 @@ -11093,7 +11076,7 @@ snapshots: prettier@3.2.5: {} - prettier@3.8.1: {} + prettier@3.8.4: {} pretty-format@27.5.1: dependencies: @@ -11124,6 +11107,8 @@ snapshots: dependencies: side-channel: 1.1.0 + quansync@1.0.0: {} + queue-microtask@1.2.3: {} range-parser@1.2.1: {} @@ -11140,10 +11125,10 @@ snapshots: react: 19.2.5 scheduler: 0.27.0 - react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002): + react-dom@19.2.7(react@19.2.7): dependencies: - react: 19.3.0-canary-a757cb76-20251002 - scheduler: 0.28.0-canary-a757cb76-20251002 + react: 19.2.7 + scheduler: 0.27.0 react-is@16.13.1: {} @@ -11151,16 +11136,16 @@ snapshots: react-is@18.3.1: {} - react-markdown@10.1.0(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002): + react-markdown@10.1.0(@types/react@19.2.17)(react@19.2.7): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@types/react': 19.2.15 + '@types/react': 19.2.17 devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 mdast-util-to-hast: 13.2.1 - react: 19.3.0-canary-a757cb76-20251002 + react: 19.2.7 remark-parse: 11.0.0 remark-rehype: 11.1.2 unified: 11.0.5 @@ -11169,63 +11154,63 @@ snapshots: transitivePeerDependencies: - supports-color - react-medium-image-zoom@5.4.5(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002): + react-medium-image-zoom@5.4.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - react: 19.3.0-canary-a757cb76-20251002 - react-dom: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) - react-redux@9.2.0(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002)(redux@5.0.1): + react-redux@9.2.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 - react: 19.3.0-canary-a757cb76-20251002 - use-sync-external-store: 1.6.0(react@19.3.0-canary-a757cb76-20251002) + react: 19.2.7 + use-sync-external-store: 1.6.0(react@19.2.7) optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.17 redux: 5.0.1 react-refresh@0.18.0: {} - react-router@7.15.1(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react@19.3.0-canary-a757cb76-20251002): + react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: cookie: 1.1.1 - react: 19.3.0-canary-a757cb76-20251002 + react: 19.2.7 set-cookie-parser: 2.7.1 optionalDependencies: - react-dom: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + react-dom: 19.2.7(react@19.2.7) - react-syntax-highlighter@16.1.1(react@19.3.0-canary-a757cb76-20251002): + react-syntax-highlighter@16.1.1(react@19.2.7): dependencies: '@babel/runtime': 7.29.2 highlight.js: 10.7.3 highlightjs-vue: 1.0.0 lowlight: 1.20.0 prismjs: 1.30.0 - react: 19.3.0-canary-a757cb76-20251002 + react: 19.2.7 refractor: 5.0.0 react@19.2.5: {} - react@19.3.0-canary-a757cb76-20251002: {} + react@19.2.7: {} read-cmd-shim@6.0.0: {} readdirp@4.1.2: {} - recharts@3.8.1(@types/react@19.2.15)(react-dom@19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002))(react-is@18.3.1)(react@19.3.0-canary-a757cb76-20251002)(redux@5.0.1): + recharts@3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@18.3.1)(react@19.2.7)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002)(redux@5.0.1))(react@19.3.0-canary-a757cb76-20251002) + '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.44.0 eventemitter3: 5.0.4 immer: 10.2.0 - react: 19.3.0-canary-a757cb76-20251002 - react-dom: 19.3.0-canary-a757cb76-20251002(react@19.3.0-canary-a757cb76-20251002) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) react-is: 18.3.1 - react-redux: 9.2.0(@types/react@19.2.15)(react@19.3.0-canary-a757cb76-20251002)(redux@5.0.1) + react-redux: 9.2.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 - use-sync-external-store: 1.6.0(react@19.3.0-canary-a757cb76-20251002) + use-sync-external-store: 1.6.0(react@19.2.7) victory-vendor: 37.3.6 transitivePeerDependencies: - '@types/react' @@ -11370,8 +11355,6 @@ snapshots: resolve-from@4.0.0: {} - resolve-from@5.0.0: {} - resolve-pkg-maps@1.0.0: {} resolve@1.22.11: @@ -11392,6 +11375,22 @@ snapshots: robust-predicates@3.0.2: {} + rolldown-plugin-dts@0.25.2(rolldown@1.1.1)(typescript@6.0.3): + dependencies: + '@babel/generator': 8.0.0-rc.6 + '@babel/helper-validator-identifier': 8.0.0-rc.6 + '@babel/parser': 8.0.0-rc.6 + ast-kit: 3.0.0-beta.1 + birpc: 4.0.0 + dts-resolver: 3.0.0 + get-tsconfig: 5.0.0-beta.5 + obug: 2.1.1 + rolldown: 1.1.1 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - oxc-resolver + rolldown@1.0.2: dependencies: '@oxc-project/types': 0.132.0 @@ -11413,36 +11412,26 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.2 '@rolldown/binding-win32-x64-msvc': 1.0.2 - rollup@4.60.4: + rolldown@1.1.1: dependencies: - '@types/estree': 1.0.8 + '@oxc-project/types': 0.135.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.4 - '@rollup/rollup-android-arm64': 4.60.4 - '@rollup/rollup-darwin-arm64': 4.60.4 - '@rollup/rollup-darwin-x64': 4.60.4 - '@rollup/rollup-freebsd-arm64': 4.60.4 - '@rollup/rollup-freebsd-x64': 4.60.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 - '@rollup/rollup-linux-arm-musleabihf': 4.60.4 - '@rollup/rollup-linux-arm64-gnu': 4.60.4 - '@rollup/rollup-linux-arm64-musl': 4.60.4 - '@rollup/rollup-linux-loong64-gnu': 4.60.4 - '@rollup/rollup-linux-loong64-musl': 4.60.4 - '@rollup/rollup-linux-ppc64-gnu': 4.60.4 - '@rollup/rollup-linux-ppc64-musl': 4.60.4 - '@rollup/rollup-linux-riscv64-gnu': 4.60.4 - '@rollup/rollup-linux-riscv64-musl': 4.60.4 - '@rollup/rollup-linux-s390x-gnu': 4.60.4 - '@rollup/rollup-linux-x64-gnu': 4.60.4 - '@rollup/rollup-linux-x64-musl': 4.60.4 - '@rollup/rollup-openbsd-x64': 4.60.4 - '@rollup/rollup-openharmony-arm64': 4.60.4 - '@rollup/rollup-win32-arm64-msvc': 4.60.4 - '@rollup/rollup-win32-ia32-msvc': 4.60.4 - '@rollup/rollup-win32-x64-gnu': 4.60.4 - '@rollup/rollup-win32-x64-msvc': 4.60.4 - fsevents: 2.3.3 + '@rolldown/binding-android-arm64': 1.1.1 + '@rolldown/binding-darwin-arm64': 1.1.1 + '@rolldown/binding-darwin-x64': 1.1.1 + '@rolldown/binding-freebsd-x64': 1.1.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.1 + '@rolldown/binding-linux-arm64-gnu': 1.1.1 + '@rolldown/binding-linux-arm64-musl': 1.1.1 + '@rolldown/binding-linux-ppc64-gnu': 1.1.1 + '@rolldown/binding-linux-s390x-gnu': 1.1.1 + '@rolldown/binding-linux-x64-gnu': 1.1.1 + '@rolldown/binding-linux-x64-musl': 1.1.1 + '@rolldown/binding-openharmony-arm64': 1.1.1 + '@rolldown/binding-wasm32-wasi': 1.1.1 + '@rolldown/binding-win32-arm64-msvc': 1.1.1 + '@rolldown/binding-win32-x64-msvc': 1.1.1 roughjs@4.6.6: dependencies: @@ -11512,8 +11501,6 @@ snapshots: scheduler@0.27.0: {} - scheduler@0.28.0-canary-a757cb76-20251002: {} - section-matter@1.0.0: dependencies: extend-shallow: 2.0.1 @@ -11523,6 +11510,8 @@ snapshots: semver@7.7.4: {} + semver@7.8.4: {} + send@1.2.1: dependencies: debug: 4.4.3 @@ -11614,6 +11603,8 @@ snapshots: shell-quote@1.8.3: {} + shell-quote@1.8.4: {} + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -11658,10 +11649,6 @@ snapshots: source-map@0.7.4: {} - source-map@0.8.0-beta.0: - dependencies: - whatwg-url: 7.1.0 - space-separated-tokens@2.0.2: {} sprintf-js@1.0.3: {} @@ -11687,11 +11674,11 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@5.1.2: + string-width@7.2.0: dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 string.prototype.codepointat@0.2.1: {} @@ -11754,9 +11741,9 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.0: + strip-ansi@7.2.0: dependencies: - ansi-regex: 6.1.0 + ansi-regex: 6.2.2 strip-bom-string@1.0.0: {} @@ -11776,25 +11763,15 @@ snapshots: dependencies: inline-style-parser: 0.2.4 - styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.3.0-canary-a757cb76-20251002): + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.7): dependencies: client-only: 0.0.1 - react: 19.3.0-canary-a757cb76-20251002 + react: 19.2.7 optionalDependencies: '@babel/core': 7.29.0 stylis@4.3.6: {} - sucrase@3.35.0: - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - commander: 4.1.1 - glob: 10.5.0 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.6 - ts-interface-checker: 0.1.13 - supabase@2.88.1: dependencies: bin-links: 6.0.0 @@ -11804,6 +11781,8 @@ snapshots: transitivePeerDependencies: - supports-color + supports-color@10.2.2: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -11842,14 +11821,6 @@ snapshots: glob: 13.0.6 minimatch: 10.2.5 - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - third-party-capital@1.0.20: {} tiny-inflate@1.0.3: {} @@ -11858,16 +11829,16 @@ snapshots: tinybench@2.9.0: {} - tinyexec@0.3.2: {} - tinyexec@1.0.2: {} - tinyglobby@0.2.15: + tinyexec@1.2.4: {} + + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - tinyglobby@0.2.16: + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 @@ -11894,10 +11865,6 @@ snapshots: dependencies: tldts: 7.0.16 - tr46@1.0.1: - dependencies: - punycode: 2.3.1 - tr46@6.0.0: dependencies: punycode: 2.3.1 @@ -11908,32 +11875,30 @@ snapshots: trough@2.2.0: {} - ts-api-utils@2.5.0(typescript@5.8.3): + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: - typescript: 5.8.3 + typescript: 6.0.3 ts-dedent@2.2.0: {} - ts-evaluator@1.2.0(jsdom@27.4.0)(typescript@5.8.3): + ts-evaluator@1.2.0(jsdom@27.4.0)(typescript@6.0.3): dependencies: ansi-colors: 4.1.3 crosspath: 2.0.0 object-path: 0.11.8 - typescript: 5.8.3 + typescript: 6.0.3 optionalDependencies: jsdom: 27.4.0 - ts-evaluator@1.2.0(jsdom@29.1.1)(typescript@5.8.3): + ts-evaluator@1.2.0(jsdom@29.1.1)(typescript@6.0.3): dependencies: ansi-colors: 4.1.3 crosspath: 2.0.0 object-path: 0.11.8 - typescript: 5.8.3 + typescript: 6.0.3 optionalDependencies: jsdom: 29.1.1 - ts-interface-checker@0.1.13: {} - ts-morph@28.0.0: dependencies: '@ts-morph/common': 0.29.0 @@ -11941,9 +11906,9 @@ snapshots: ts-pattern@5.9.0: {} - tsconfck@3.1.6(typescript@5.8.3): + tsconfck@3.1.6(typescript@6.0.3): optionalDependencies: - typescript: 5.8.3 + typescript: 6.0.3 tsconfig-paths@3.15.0: dependencies: @@ -11952,61 +11917,33 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tslib@2.8.1: {} - - tsup@8.4.0(jiti@2.4.2)(postcss@8.5.14)(tsx@4.22.3)(typescript@5.8.3): + tsdown@0.22.2(tsx@4.22.3)(typescript@6.0.3): dependencies: - bundle-require: 5.1.0(esbuild@0.25.12) - cac: 6.7.14 - chokidar: 4.0.3 - consola: 3.4.2 - debug: 4.4.3 - esbuild: 0.25.12 - joycon: 3.1.1 - picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.14)(tsx@4.22.3) - resolve-from: 5.0.0 - rollup: 4.60.4 - source-map: 0.8.0-beta.0 - sucrase: 3.35.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 + ansis: 4.3.1 + cac: 7.0.0 + defu: 6.1.7 + empathic: 2.0.1 + hookable: 6.1.1 + import-without-cache: 0.4.0 + obug: 2.1.1 + picomatch: 4.0.4 + rolldown: 1.1.1 + rolldown-plugin-dts: 0.25.2(rolldown@1.1.1)(typescript@6.0.3) + semver: 7.8.4 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 tree-kill: 1.2.2 + unconfig-core: 7.5.0 optionalDependencies: - postcss: 8.5.14 - typescript: 5.8.3 + tsx: 4.22.3 + typescript: 6.0.3 transitivePeerDependencies: - - jiti - - supports-color - - tsx - - yaml + - '@ts-macro/tsc' + - '@typescript/native-preview' + - oxc-resolver + - vue-tsc - tsup@8.4.0(jiti@2.4.2)(postcss@8.5.14)(tsx@4.22.3)(typescript@5.9.3): - dependencies: - bundle-require: 5.1.0(esbuild@0.25.12) - cac: 6.7.14 - chokidar: 4.0.3 - consola: 3.4.2 - debug: 4.4.3 - esbuild: 0.25.12 - joycon: 3.1.1 - picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.14)(tsx@4.22.3) - resolve-from: 5.0.0 - rollup: 4.60.4 - source-map: 0.8.0-beta.0 - sucrase: 3.35.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tree-kill: 1.2.2 - optionalDependencies: - postcss: 8.5.14 - typescript: 5.9.3 - transitivePeerDependencies: - - jiti - - supports-color - - tsx - - yaml + tslib@2.8.1: {} tsx@4.22.3: dependencies: @@ -12014,14 +11951,14 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - turbo@2.9.5: + turbo@2.9.18: optionalDependencies: - '@turbo/darwin-64': 2.9.5 - '@turbo/darwin-arm64': 2.9.5 - '@turbo/linux-64': 2.9.5 - '@turbo/linux-arm64': 2.9.5 - '@turbo/windows-64': 2.9.5 - '@turbo/windows-arm64': 2.9.5 + '@turbo/darwin-64': 2.9.18 + '@turbo/darwin-arm64': 2.9.18 + '@turbo/linux-64': 2.9.18 + '@turbo/linux-arm64': 2.9.18 + '@turbo/windows-64': 2.9.18 + '@turbo/windows-arm64': 2.9.18 type-check@0.4.0: dependencies: @@ -12072,23 +12009,21 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3): + typescript-eslint@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.8.3) - '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3))(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) + '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.3) + '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.4.2))(typescript@6.0.3) eslint: 9.39.4(jiti@2.4.2) - typescript: 5.8.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color - typescript@5.8.3: {} - - typescript@5.9.3: {} - typescript@6.0.2: {} + typescript@6.0.3: {} + ufo@1.6.1: {} unbox-primitive@1.1.0: @@ -12098,6 +12033,11 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + unconfig-core@7.5.0: + dependencies: + '@quansync/fs': 1.0.0 + quansync: 1.0.0 + undici-types@7.24.6: {} undici@7.25.0: {} @@ -12167,9 +12107,9 @@ snapshots: dependencies: punycode: 2.3.1 - use-sync-external-store@1.6.0(react@19.3.0-canary-a757cb76-20251002): + use-sync-external-store@1.6.0(react@19.2.7): dependencies: - react: 19.3.0-canary-a757cb76-20251002 + react: 19.2.7 util-deprecate@1.0.2: {} @@ -12215,11 +12155,11 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-tsconfig-paths@6.1.1(typescript@5.8.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)): + vite-tsconfig-paths@6.1.1(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)): dependencies: debug: 4.4.1 globrex: 0.1.2 - tsconfck: 3.1.6(typescript@5.8.3) + tsconfck: 3.1.6(typescript@6.0.3) vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3) transitivePeerDependencies: - supports-color @@ -12239,10 +12179,10 @@ snapshots: jiti: 2.4.2 tsx: 4.22.3 - vitest@4.1.4(@types/node@25.9.1)(jsdom@27.4.0)(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)): + vitest@4.1.4(@types/node@25.9.1)(jsdom@27.4.0)(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)): dependencies: '@vitest/expect': 4.1.4 - '@vitest/mocker': 4.1.4(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) + '@vitest/mocker': 4.1.4(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) '@vitest/pretty-format': 4.1.4 '@vitest/runner': 4.1.4 '@vitest/snapshot': 4.1.4 @@ -12267,10 +12207,10 @@ snapshots: transitivePeerDependencies: - msw - vitest@4.1.4(@types/node@25.9.1)(jsdom@29.1.1)(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)): + vitest@4.1.4(@types/node@25.9.1)(jsdom@29.1.1)(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)): dependencies: '@vitest/expect': 4.1.4 - '@vitest/mocker': 4.1.4(msw@2.13.2(@types/node@25.9.1)(typescript@5.8.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) + '@vitest/mocker': 4.1.4(msw@2.13.2(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.4.2)(tsx@4.22.3)) '@vitest/pretty-format': 4.1.4 '@vitest/runner': 4.1.4 '@vitest/snapshot': 4.1.4 @@ -12303,8 +12243,6 @@ snapshots: web-streams-polyfill@3.3.3: {} - webidl-conversions@4.0.2: {} - webidl-conversions@8.0.0: {} webidl-conversions@8.0.1: {} @@ -12328,12 +12266,6 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - whatwg-url@7.1.0: - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -12409,11 +12341,11 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - wrap-ansi@8.1.0: + wrap-ansi@9.0.2: dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 wrappy@1.0.2: {} @@ -12436,6 +12368,8 @@ snapshots: yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -12446,6 +12380,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yocto-queue@0.1.0: {} yocto-queue@1.2.2: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a314e322..623bdaa1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -21,7 +21,6 @@ overrides: 'picomatch@4': 4.0.4 postcss: 8.5.14 'qs@6': 6.15.1 - 'rollup@4': 4.60.4 'tough-cookie@2': 4.1.4 'uuid@11': 11.1.1 @@ -35,13 +34,8 @@ allowBuilds: catalog: '@pandacss/dev': 1.11.1 'next': 16.2.6 - -catalogs: - react19: - react: ^19.3.0-canary-a757cb76-20251002 - react-dom: ^19.3.0-canary-a757cb76-20251002 - '@types/react': ^19.2.14 - '@types/react-dom': ^19.2.0 - - typescript5: - typescript: 5.8.3 + typescript: 6.0.3 + react: 19.2.7 + react-dom: 19.2.7 + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3