From f194bd7cb2ce2576088e66dba5814ecdbc0296c3 Mon Sep 17 00:00:00 2001 From: yujeong-jeon Date: Mon, 11 May 2026 15:29:02 +0900 Subject: [PATCH 1/3] =?UTF-8?q?:memo:=20docs:=20Claude=20Code=20=EA=B0=80?= =?UTF-8?q?=EC=9D=B4=EB=93=9C=20=EB=AC=B8=EC=84=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 루트 및 각 패키지에 CLAUDE.md 파일을 추가합니다. 루트 CLAUDE.md는 모노레포 전체 구조, 빌드/테스트 명령, 컨벤션을 담고, 각 패키지 CLAUDE.md는 해당 패키지의 아키텍처, 공개 API, 주요 설계 결정을 상세히 기술합니다. --- CLAUDE.md | 81 +++++++++++++++++++++++ packages/es-http-status-codes/CLAUDE.md | 45 +++++++++++++ packages/react-pdf/CLAUDE.md | 57 ++++++++++++++++ packages/safe-html-react-parser/CLAUDE.md | 46 +++++++++++++ packages/svg-manager/CLAUDE.md | 47 +++++++++++++ packages/url-param-compressor/CLAUDE.md | 53 +++++++++++++++ packages/utils/CLAUDE.md | 74 +++++++++++++++++++++ packages/vanilla-store/CLAUDE.md | 63 ++++++++++++++++++ 8 files changed, 466 insertions(+) create mode 100644 CLAUDE.md create mode 100644 packages/es-http-status-codes/CLAUDE.md create mode 100644 packages/react-pdf/CLAUDE.md create mode 100644 packages/safe-html-react-parser/CLAUDE.md create mode 100644 packages/svg-manager/CLAUDE.md create mode 100644 packages/url-param-compressor/CLAUDE.md create mode 100644 packages/utils/CLAUDE.md create mode 100644 packages/vanilla-store/CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e9937b6 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,81 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +`pie` is a monorepo of common frontend libraries maintained by the Naver Financial frontend team. It uses pnpm workspaces + Turborepo, with packages under `packages/*` and internal apps under `apps/*`. + +## Commands + +```bash +# Install dependencies +pnpm install + +# Build all packages (respects dependency order via Turborepo) +pnpm run build + +# Run all tests +pnpm run test + +# Filter to a specific package +pnpm run build --filter @naverpay/utils +pnpm run test --filter @naverpay/utils + +# Run tests inside a package directly +cd packages/utils && pnpm test + +# Lint / format +pnpm run lint +pnpm run lint:fix +pnpm run prettier +pnpm run prettier:fix + +# Docs dev server +pnpm run start --filter docs + +# Full clean + reinstall +pnpm run clean +``` + +## Packages + +Each package has its own `CLAUDE.md` with detailed architecture and API notes: + +| Package | Description | CLAUDE.md | +|---|---|---| +| `@naverpay/utils` | JS/TS utility functions (formatting, masking, Korean language) | [packages/utils/CLAUDE.md](packages/utils/CLAUDE.md) | +| `@naverpay/vanilla-store` | Framework-agnostic state management with React hooks | [packages/vanilla-store/CLAUDE.md](packages/vanilla-store/CLAUDE.md) | +| `@naverpay/url-param-compressor` | URL query param compression via deflate + base64 | [packages/url-param-compressor/CLAUDE.md](packages/url-param-compressor/CLAUDE.md) | +| `@naverpay/safe-html-react-parser` | DOMPurify + html-react-parser safe wrapper | [packages/safe-html-react-parser/CLAUDE.md](packages/safe-html-react-parser/CLAUDE.md) | +| `@naverpay/react-pdf` | Korean-optimized PDF viewer (pdfjs-dist) | [packages/react-pdf/CLAUDE.md](packages/react-pdf/CLAUDE.md) | +| `@naverpay/svg-manager` | SVG unique ID scoping for React | [packages/svg-manager/CLAUDE.md](packages/svg-manager/CLAUDE.md) | +| `@naverpay/es-http-status-codes` | Auto-generated HTTP status code constants | [packages/es-http-status-codes/CLAUDE.md](packages/es-http-status-codes/CLAUDE.md) | + +## Architecture + +### Build + +All packages build with `@naverpay/pite` (`createViteConfig`) and output both CJS (`dist/cjs/`) and ESM (`dist/esm/`). Each package's `vite.config.mjs` declares the entry point(s). + +### Testing + +- Most packages: **vitest** + **happy-dom** +- `es-http-status-codes`: **jest** + **ts-jest** +- `url-param-compressor`: **vitest** (Node) + **playwright** (browser) — both run on `pnpm test` + +### Versioning + +Uses **changesets**. Before merging a PR, create a changeset file with `pnpm changeset`. Base branch is `main`. Internal dependency updates default to `patch`. + +### Code Quality + +Enforced via ESLint (`@naverpay/eslint-config`), Prettier (`@naverpay/prettier-config`), and markdownlint (`@naverpay/markdown-lint`). husky + lint-staged run checks on every commit. + +## Conventions + +- **No breaking changes**: Avoid changes that require consumers to update their code. +- **`sideEffects: false`**: All packages declare this — do not add side effects at module load time. +- **pnpm catalog**: React-related peer dependency versions are unified in `pnpm-workspace.yaml` under `catalog:`. Use `catalog:` instead of hardcoded version ranges. +- **Test file location**: `__tests__/` directory at package root (for `utils`, `es-http-status-codes`); colocated in `src/` for `vanilla-store` and `url-param-compressor`. +- **Auto-generated files**: `packages/es-http-status-codes/src/status-code.ts` and `reason-phrase.ts` are generated — never edit directly. diff --git a/packages/es-http-status-codes/CLAUDE.md b/packages/es-http-status-codes/CLAUDE.md new file mode 100644 index 0000000..33f4482 --- /dev/null +++ b/packages/es-http-status-codes/CLAUDE.md @@ -0,0 +1,45 @@ +# CLAUDE.md — @naverpay/es-http-status-codes + +Auto-generated, tree-shakable HTTP status code constants and reason phrases for TypeScript/JavaScript. + +## Commands + +```bash +pnpm generate # regenerate src/ from data.json +pnpm test # jest + ts-jest +pnpm build # CJS + ESM +``` + +## Structure + +``` +data.json # source of truth — list of { code, phrase, constant } +script/index.js # code generator: reads data.json → writes src/ +src/ + status-code.ts # AUTO-GENERATED: HttpStatusCodes, HttpStatusCode, HttpStatusCodeKeys + reason-phrase.ts # AUTO-GENERATED: ReasonPhrases + index.ts # re-exports both +__tests__/ + index.test.ts # jest tests +``` + +## Key Rule + +**Never edit `src/status-code.ts` or `src/reason-phrase.ts` directly.** They are auto-generated with the header comment `/*This file is auto-generated. Do not edit directly.*/`. + +To add or change HTTP status codes, edit `data.json` and run `pnpm generate`. + +## Public API + +```ts +import { HttpStatusCodes, ReasonPhrases } from '@naverpay/es-http-status-codes' + +HttpStatusCodes.OK // 200 +HttpStatusCodes.NOT_FOUND // 404 +ReasonPhrases[200] // "OK" + +// Types +type HttpStatusCode // union of all numeric codes +type HttpStatusCodeKey // union of all constant name strings +HttpStatusCodeKeys // string[] of all constant names +``` diff --git a/packages/react-pdf/CLAUDE.md b/packages/react-pdf/CLAUDE.md new file mode 100644 index 0000000..14602c3 --- /dev/null +++ b/packages/react-pdf/CLAUDE.md @@ -0,0 +1,57 @@ +# CLAUDE.md — @naverpay/react-pdf + +React PDF viewer built on `pdfjs-dist`, optimized for Korean documents. Exports CSS separately (`@naverpay/react-pdf/style.css`). + +## Commands + +```bash +pnpm build # CJS + ESM (no tests in this package) +``` + +## Structure + +``` +src/ + index.ts # public exports + components/ + PdfViewer.tsx # top-level component (entry point for consumers) + Pages.tsx # renders all pages via IntersectionObserver + page/ + Canvas.tsx # renders a single PDF page onto + layer/ + Text.tsx # text layer (enables text selection) + Annotation.tsx # annotation layer (links, etc.) + contexts/ + pdf.tsx # PDFDocumentProxy + viewer config context + page.tsx # per-page context + hooks/ + useInfiniteScroll.ts # IntersectionObserver-based lazy page loading + useIsomorphicLayoutEffect.ts # useLayoutEffect on client, useEffect on SSR + usePdfViewerPageWidth.ts # measures container width for responsive rendering + utils/ + pdf.ts # getPdfDocument wrapper + text.ts # text layer utilities + link-service.ts # external link handling for annotations + debounce.ts # local debounce (not from @naverpay/utils) +``` + +## PdfViewer Props + +Key props on ``: + +- `pdfUrl` — required, URL of the PDF file +- `pdfWorkerSource` — path to `pdf.worker.js` (consumers must configure) +- `cMapUrl`, `cMapCompressed` — for older PDFs requiring cmap support (Korean fonts) +- `withCredentials` — passes cookies for authenticated PDF endpoints +- `lazyLoading` — default `true`, uses IntersectionObserver for deferred page rendering +- `onClickWords` — `{ target: string | RegExp, callback }[]` for clickable text +- `header`, `footer` — ReactNode rendered above/below the PDF pages +- `onLoadPDFRender`, `onErrorPDFRender` — load lifecycle callbacks +- `externalLinkTarget` — default `'_blank'` + +## Key Details + +- PDF fingerprint comparison prevents unnecessary re-renders when `pdfUrl` doesn't change. +- `tokenize` prop is automatically set to `true` when `onClickWords` is provided. +- Consumers must import `@naverpay/react-pdf/style.css` separately. +- No tests exist in this package currently. diff --git a/packages/safe-html-react-parser/CLAUDE.md b/packages/safe-html-react-parser/CLAUDE.md new file mode 100644 index 0000000..d206a2e --- /dev/null +++ b/packages/safe-html-react-parser/CLAUDE.md @@ -0,0 +1,46 @@ +# CLAUDE.md — @naverpay/safe-html-react-parser + +Wraps `html-react-parser` with `isomorphic-dompurify` to sanitize HTML before parsing into React elements. Works in both SSR (Node) and browser environments. + +## Commands + +```bash +pnpm run test:memory # vitest run (no watch) +pnpm build # CJS + ESM +``` + +## Structure + +``` +src/ + index.ts # safeParse(), SafeParseOptions, DEFAULT_SANITIZE_CONFIG + utils/ + dompurify.ts # thin wrapper around isomorphic-dompurify +``` + +## Public API + +```ts +safeParse(htmlString: string, options?: SafeParseOptions): ReactNode | null +``` + +`SafeParseOptions` extends `HTMLReactParserOptions` with: + +- `sanitizeConfig?: SanitizeConfig` — DOMPurify config (defaults to `DEFAULT_SANITIZE_CONFIG`) +- `preserveCustomTags?: string[]` — custom elements to preserve through sanitization + +`DEFAULT_SANITIZE_CONFIG` allows: `p br strong em b i u span div h1-h6 h ul ol li dl dt dd a img` with `KEEP_CONTENT: true`. + +## Key Design Decisions + +**CJS/ESM interop quirk**: `html-react-parser` re-exports its CJS default in a non-standard way. The actual parse function is resolved as: + +```ts +htmlReactParser.default?.default || htmlReactParser.default || htmlReactParser +``` + +Do not change this without verifying both CJS and ESM builds. + +**Custom tag preservation**: DOMPurify strips unknown tags. To preserve custom tags, `preserveCustomTags` temporarily converts them to `` before sanitization, then restores them via the `replace` option in `html-react-parser`. + +**Returns `null`** if the sanitized HTML is empty/falsy. diff --git a/packages/svg-manager/CLAUDE.md b/packages/svg-manager/CLAUDE.md new file mode 100644 index 0000000..6a18b85 --- /dev/null +++ b/packages/svg-manager/CLAUDE.md @@ -0,0 +1,47 @@ +# CLAUDE.md — @naverpay/svg-manager + +React utility for making SVG `id` attributes unique across multiple instances of the same SVG component. + +## Commands + +```bash +pnpm build # CJS + ESM (no tests in this package) +``` + +## Structure + +``` +src/ + SvgUniqueID.tsx # main component + index.ts # exports: SvgUniqueID, toSingleton, SVGStyleProps + utils/ + index.ts # generateRandomString, toSingleton + deepMap.ts # recursive React children traversal + getSecureMathRandom.ts + types/ + svg.ts # SVGStyleProps type + utility-types.ts +``` + +## How It Works + +`SvgUniqueID` wraps SVG children and rewrites all `id`, `url(#...)`, and `xlinkHref="#..."` references to unique scoped values using a `prefixId` + random instance `id`. + +- Uses a module-level singleton `Map` (`localIdsMap`) to track original → local ID mapping per render. +- Recursively traverses children with `deepMap` (custom recursive `cloneElement`). +- `toSingleton` is a utility that creates a factory returning the same instance on every call. + +## Props + +```tsx + + {/* SVG content with id/url(#...)/xlinkHref attributes */} + +``` + +## No Tests + +This package currently has no test suite. diff --git a/packages/url-param-compressor/CLAUDE.md b/packages/url-param-compressor/CLAUDE.md new file mode 100644 index 0000000..95122f0 --- /dev/null +++ b/packages/url-param-compressor/CLAUDE.md @@ -0,0 +1,53 @@ +# CLAUDE.md — @naverpay/url-param-compressor + +Compresses URL query parameters using deflate (fflate) + URL-safe base64 encoding. Runs in both Node and browser environments. + +## Commands + +```bash +pnpm test # runs both node and browser tests +pnpm run test:node # vitest only +pnpm run test:browser # playwright only +pnpm bench # vitest benchmark +pnpm build # CJS + ESM +``` + +## Structure + +``` +src/ + URLParamCompressor.ts # main class + URLParamCompressor.test.ts # vitest unit tests + URLParamCompressor.bench.ts # benchmark + utils/ + LRUCache.ts # in-memory cache for decompress results + index.ts +``` + +## How It Works + +`URLParamCompressor` is a class with three methods: + +- **`compress(urlObj)`** — serializes `Record` via `URLSearchParams`, compresses with `deflateSync`, encodes to URL-safe base64. If compressed is _larger_ than original, returns the uncompressed string. + - Returns `{ result: string, isCompressed: boolean }` + +- **`decompress(compressed)`** — reverses compress. Caches result in `LRUCache`. Returns `null` on failure. + +- **`get(compressed, key)`** — extracts a single key from a compressed string, using cache to avoid re-decompressing. + +## Constructor Options + +```ts +new URLParamCompressor({ + cacheCapacity?: number // default 100 + debug?: boolean // logs compression ratio or skip reason + deflateOptions?: { level?, mem?, dictionary? } +}) +``` + +## Key Details + +- Uses `Buffer` in Node, `btoa`/`atob` in browser — both paths are handled internally. +- URL-safe base64: `+` → `-`, `/` → `_`, trailing `=` removed. +- The `LRUCache` prevents repeated decompression of the same string. +- Playwright tests verify browser environment compatibility. diff --git a/packages/utils/CLAUDE.md b/packages/utils/CLAUDE.md new file mode 100644 index 0000000..0d86726 --- /dev/null +++ b/packages/utils/CLAUDE.md @@ -0,0 +1,74 @@ +# CLAUDE.md — @naverpay/utils + +JavaScript/TypeScript utility library for Naver Financial frontend teams. + +## Commands + +```bash +# Run all tests (watch=false) +pnpm test + +# Build (CJS + ESM via vite) +pnpm build +``` + +## Structure + +``` +src/ + index.ts # re-exports everything + utils/ # one file per utility + constants/ + hangul.ts # Korean character constants +__tests__/ # test files mirror utils/ names +``` + +## Exported Utilities + +**Number / String Formatting** + +- `formatNumberWithComma` — adds thousand separators +- `formatTenThousandUnitsAmount` — Korean 만(萬) unit formatting +- `createNumberFormatter` — factory for locale-aware number formatters +- `formatKoreanPhoneNumber` — formats raw digits to `010-XXXX-XXXX` +- `formatBusinessRegistrationNumber` — formats to `XXX-XX-XXXXX` + +**Masking** + +- `maskString`, `maskEmail`, `maskPhoneNumber`, `maskAccountNumber`, `maskCardNumber`, `maskPassportNumber` + +**Korean Language** + +- `get조사`, `with조사` — attaches Korean postpositions (은/는, 이/가, etc.) +- `getKoreanWithSuffix` — appends Korean suffix based on final consonant +- `마지막_문자_받침_여부` — checks if last character has a final consonant (받침) +- `한글_여부` — checks if a character is Korean +- `disassemble문자` — decomposes Korean characters into jamo + +**Validation** + +- `isValidKoreanPhoneNumber`, `isValidBusinessRegistrationNumber` + +**Async / Performance** + +- `debounce`, `throttle`, `sleep` +- `DeferredPromise` — exposes `resolve`/`reject` externally + +**Misc** + +- `isEmpty` — null/undefined/empty string/array/object check +- `deepMerge` — deep object merge +- `createKeyValuePairObject` — creates typed key-value pair objects +- `createSeededRandom` — deterministic pseudo-random number generator +- `getSecureMathRandom` — `crypto.getRandomValues`-based random (browser/server split) +- `generateRandomString`, `getRandomNumber` +- `encodeHTMLEntity` — HTML entity encoding +- `replaceNoBreakSpace` — replaces `\u00A0` with normal space +- `backOrClose` — browser back or window close + +## Conventions + +- Each utility lives in its own file under `src/utils/`. Do not merge unrelated utilities. +- Korean-named files (e.g., `한글_여부.ts`) are intentional — keep the naming. +- `getSecureMathRandom` has a `browser.ts` / `server.ts` split; the entry resolves via vite build conditions. +- Tests live in `__tests__/`, using vitest + happy-dom environment. diff --git a/packages/vanilla-store/CLAUDE.md b/packages/vanilla-store/CLAUDE.md new file mode 100644 index 0000000..9c0009c --- /dev/null +++ b/packages/vanilla-store/CLAUDE.md @@ -0,0 +1,63 @@ +# CLAUDE.md — @naverpay/vanilla-store + +Framework-agnostic state management library with optional React bindings and persistence support. + +## Commands + +```bash +pnpm test # vitest, watch=false +pnpm build # CJS + ESM +``` + +## Architecture + +``` +src/ + store.ts # createVanillaStore — core store primitive + react.ts # React hooks (useStore, useGetStore, useSetStore, useStoreSelector) + select.ts # createVanillaSelect — derived/computed stores + shallowEqual.ts # default equality function + type.ts # shared types (VanillaStore, VanillaSelect, SetAction, Options, ...) + applyOptions.ts # wires persist plugin into the store lifecycle + persist/ + type.ts # abstract Persistent base class + LocalStoragePersist.ts + SessionStoragePersist.ts + index.ts +``` + +## Key Design Decisions + +**Server-side safety**: `createVanillaStore` detects `typeof window === 'undefined'` and returns a read-only store on the server. Calling `set` on the server logs a descriptive error and returns `initialState` — it does NOT throw. + +**Equality**: Defaults to `shallowEqual`. Pass a custom `equalityFn` as the second argument to `createVanillaStore` to override. + +**Persistence**: Pass `options` (third argument) to opt into `LocalStoragePersist` or `SessionStoragePersist`. The persist plugin is applied only on the client. + +**React integration**: Uses `useSyncExternalStore`. `useStoreSelector` implements a ref-based selector to avoid unnecessary re-renders without requiring an external selector library. + +**`createVanillaSelect`**: Creates a derived store (read-only). Hooks accept both `VanillaStore` and `VanillaSelect` — TypeScript overloads enforce that `set` is `never` for selects. + +## Public API + +```ts +// Core +createVanillaStore(initialState, equalityFn?, options?) + +// React hooks +useStore(store, initialValue?) // [value, set] +useGetStore(store, initialValue?) // value only +useSetStore(store, initialValue?) // set only +useStoreSelector(store, selector, options?) // [selectedValue, set] + +// Derived store +createVanillaSelect(store, selector) + +// Persistence +new LocalStoragePersist(key, initialValue, typeAssertion) +new SessionStoragePersist(key, initialValue, typeAssertion) +``` + +## Tests + +Tests are colocated in `src/` (`store.test.ts`, `react.test.ts`, `select.test.ts`), using vitest + happy-dom. From 02da5036c7871c8beacde0d54872a52d26a83e54 Mon Sep 17 00:00:00 2001 From: yujeong-jeon Date: Mon, 11 May 2026 15:31:55 +0900 Subject: [PATCH 2/3] =?UTF-8?q?:memo:=20docs:=20=EA=B0=81=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=EC=97=90=20llms.txt=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LLM이 패키지를 이해할 수 있도록 각 패키지에 llms.txt 파일을 추가하고, npm 배포 시 포함되도록 package.json의 files 배열에 등록합니다. --- packages/es-http-status-codes/llms.txt | 41 ++++++++++++ packages/es-http-status-codes/package.json | 3 +- packages/react-pdf/llms.txt | 53 ++++++++++++++++ packages/react-pdf/package.json | 3 +- packages/safe-html-react-parser/llms.txt | 48 ++++++++++++++ packages/safe-html-react-parser/package.json | 3 +- packages/svg-manager/llms.txt | 54 ++++++++++++++++ packages/svg-manager/package.json | 3 +- packages/url-param-compressor/llms.txt | 47 ++++++++++++++ packages/url-param-compressor/package.json | 3 +- packages/utils/llms.txt | 62 ++++++++++++++++++ packages/utils/package.json | 3 +- packages/vanilla-store/llms.txt | 67 ++++++++++++++++++++ packages/vanilla-store/package.json | 3 +- 14 files changed, 386 insertions(+), 7 deletions(-) create mode 100644 packages/es-http-status-codes/llms.txt create mode 100644 packages/react-pdf/llms.txt create mode 100644 packages/safe-html-react-parser/llms.txt create mode 100644 packages/svg-manager/llms.txt create mode 100644 packages/url-param-compressor/llms.txt create mode 100644 packages/utils/llms.txt create mode 100644 packages/vanilla-store/llms.txt diff --git a/packages/es-http-status-codes/llms.txt b/packages/es-http-status-codes/llms.txt new file mode 100644 index 0000000..389ab8b --- /dev/null +++ b/packages/es-http-status-codes/llms.txt @@ -0,0 +1,41 @@ +# @naverpay/es-http-status-codes + +> Lightweight, tree-shakable HTTP status code constants and reason phrases for TypeScript/JavaScript. Auto-generated from a canonical data source, ESM-compatible. + +## Installation + +```bash +npm install @naverpay/es-http-status-codes +``` + +## Usage + +```ts +import { HttpStatusCodes, ReasonPhrases, HttpStatusCodeKeys } from '@naverpay/es-http-status-codes' + +// Status code constants +HttpStatusCodes.OK // 200 +HttpStatusCodes.NOT_FOUND // 404 +HttpStatusCodes.INTERNAL_SERVER_ERROR // 500 + +// Reason phrases by numeric code +ReasonPhrases[200] // "OK" +ReasonPhrases[404] // "Not Found" +ReasonPhrases[500] // "Internal Server Error" + +// All constant name strings +HttpStatusCodeKeys // ['CONTINUE', 'SWITCHING_PROTOCOLS', 'OK', ...] +``` + +## Types + +```ts +type HttpStatusCode // union of all numeric status codes: 100 | 101 | 200 | 201 | ... +type HttpStatusCodeKey // union of all constant name strings: 'OK' | 'NOT_FOUND' | ... +``` + +## Notes + +- `HttpStatusCodes` is a `const` object — values are inferred as literal number types, enabling exhaustive checks. +- `sideEffects: false` — individual constants are tree-shakable in bundlers that support it. +- The source files (`src/status-code.ts`, `src/reason-phrase.ts`) are auto-generated from `data.json`. Do not edit them directly. diff --git a/packages/es-http-status-codes/package.json b/packages/es-http-status-codes/package.json index 8f656a7..492cad7 100644 --- a/packages/es-http-status-codes/package.json +++ b/packages/es-http-status-codes/package.json @@ -42,7 +42,8 @@ "./package.json": "./package.json" }, "files": [ - "dist" + "dist", + "llms.txt" ], "scripts": { "clean": "rm -rf dist", diff --git a/packages/react-pdf/llms.txt b/packages/react-pdf/llms.txt new file mode 100644 index 0000000..b3067c0 --- /dev/null +++ b/packages/react-pdf/llms.txt @@ -0,0 +1,53 @@ +# @naverpay/react-pdf + +> React PDF viewer component built on pdfjs-dist, optimized for Korean documents. Supports lazy page loading, text selection, annotation layers, and clickable word callbacks. + +## Installation + +```bash +npm install @naverpay/react-pdf +``` + +Import the stylesheet separately: + +```ts +import '@naverpay/react-pdf/style.css' +``` + +## Usage + +```tsx +import { PdfViewer } from '@naverpay/react-pdf' +import '@naverpay/react-pdf/style.css' + + console.log('loaded')} + onErrorPDFRender={(e) => console.error(e)} +/> +``` + +## Props + +| Prop | Type | Default | Description | +|---|---|---|---| +| `pdfUrl` | `string` | required | URL of the PDF file | +| `pdfWorkerSource` | `string` | — | Path to `pdf.worker.js` | +| `cMapUrl` | `string` | — | URL for cmap files (Korean font support for older PDFs) | +| `cMapCompressed` | `boolean` | — | Whether cmap files are compressed | +| `withCredentials` | `boolean` | — | Send cookies with the PDF request | +| `lazyLoading` | `boolean` | `true` | Defer rendering of off-screen pages via IntersectionObserver | +| `externalLinkTarget` | `string` | `'_blank'` | Target for annotation links | +| `onClickWords` | `{ target: string \| RegExp, callback: () => void }[]` | — | Callbacks for clicking specific words in the text layer | +| `header` | `ReactNode` | — | Rendered above the PDF pages | +| `footer` | `ReactNode` | — | Rendered below the PDF pages | +| `style` | `CSSProperties` | `{}` | Style for the outermost container `
` | +| `onLoadPDFRender` | `() => void` | — | Called after PDF loads successfully | +| `onErrorPDFRender` | `(e: unknown) => void` | — | Called if PDF loading fails | + +## Notes + +- The consumer is responsible for hosting `pdf.worker.js` and providing its path via `pdfWorkerSource`. +- `tokenize` is automatically enabled when `onClickWords` is provided. +- PDF fingerprints are compared to avoid re-rendering when the same URL reloads. diff --git a/packages/react-pdf/package.json b/packages/react-pdf/package.json index a9f3745..08646ad 100644 --- a/packages/react-pdf/package.json +++ b/packages/react-pdf/package.json @@ -38,7 +38,8 @@ "react-pdf" ], "files": [ - "dist" + "dist", + "llms.txt" ], "scripts": { "clean": "rm -rf dist", diff --git a/packages/safe-html-react-parser/llms.txt b/packages/safe-html-react-parser/llms.txt new file mode 100644 index 0000000..8aba7fc --- /dev/null +++ b/packages/safe-html-react-parser/llms.txt @@ -0,0 +1,48 @@ +# @naverpay/safe-html-react-parser + +> A secure wrapper that sanitizes HTML with DOMPurify (isomorphic-dompurify) before parsing it into React elements with html-react-parser. Works in SSR and browser environments. + +## Installation + +```bash +npm install @naverpay/safe-html-react-parser +``` + +## Usage + +```tsx +import { safeParse } from '@naverpay/safe-html-react-parser' + +// Basic usage — uses DEFAULT_SANITIZE_CONFIG +const element = safeParse('

Hello world

') + +// Custom DOMPurify config +const element = safeParse(html, { + sanitizeConfig: { + ALLOWED_TAGS: ['p', 'strong', 'em', 'a'], + ALLOWED_ATTR: ['href'], + }, +}) + +// Preserve custom tags (e.g. ) through sanitization +const element = safeParse(html, { + preserveCustomTags: ['highlight'], +}) + +// Pass html-react-parser options (e.g. replace) +const element = safeParse(html, { + replace: (domNode) => { /* ... */ }, +}) +``` + +## Default Allowed Tags + +`p br strong em b i u span div h1 h2 h3 h4 h5 h6 h ul ol li dl dt dd a img` + +`KEEP_CONTENT: true` — when a disallowed tag is stripped, its text content is preserved. + +## Notes + +- Returns `null` if the sanitized result is empty. +- `preserveCustomTags` works by temporarily converting unknown tags to `` before sanitization, then restoring them. Only works for simple wrapping tags without attributes. +- The internal CJS/ESM resolution of `html-react-parser` is handled automatically — do not re-import `parse` directly. diff --git a/packages/safe-html-react-parser/package.json b/packages/safe-html-react-parser/package.json index ca72c38..04110e7 100644 --- a/packages/safe-html-react-parser/package.json +++ b/packages/safe-html-react-parser/package.json @@ -52,7 +52,8 @@ "./package.json": "./package.json" }, "files": [ - "dist" + "dist", + "llms.txt" ], "sideEffects": false, "homepage": "https://naverpaydev.github.io/pie/docs/@naverpay/safe-html-react-parser/" diff --git a/packages/svg-manager/llms.txt b/packages/svg-manager/llms.txt new file mode 100644 index 0000000..ec0c0b6 --- /dev/null +++ b/packages/svg-manager/llms.txt @@ -0,0 +1,54 @@ +# @naverpay/svg-manager + +> React component that makes SVG `id` attributes unique across multiple instances of the same inline SVG, preventing ID collisions in the DOM. + +## Installation + +```bash +npm install @naverpay/svg-manager +``` + +## Problem + +When the same SVG component is rendered multiple times, `id` attributes (used for gradients, masks, clip paths, etc.) collide in the DOM because IDs must be globally unique. `SvgUniqueID` rewrites all `id`, `url(#...)`, and `xlinkHref="#..."` references to scoped unique values per instance. + +## Usage + +```tsx +import { SvgUniqueID } from '@naverpay/svg-manager' + +function MyIcon() { + return ( + + + + ... + + + + + ) +} + +// Render multiple times — IDs are automatically scoped per instance + + +``` + +## Props + +| Prop | Type | Default | Description | +|---|---|---|---| +| `prefixId` | `string` | `'__SVG_ID__'` | Prefix for generated IDs | +| `id` | `string` | `generateRandomString()` | Unique identifier for this instance (auto-generated) | +| `children` | `ReactNode` | required | SVG content to scope | + +## Exports + +```ts +import { SvgUniqueID, toSingleton } from '@naverpay/svg-manager' +import type { SVGStyleProps } from '@naverpay/svg-manager' +``` + +- `toSingleton(factory)` — wraps a factory function so it returns the same instance on every call +- `SVGStyleProps` — TypeScript type for SVG style properties diff --git a/packages/svg-manager/package.json b/packages/svg-manager/package.json index 63fc330..b479ccf 100644 --- a/packages/svg-manager/package.json +++ b/packages/svg-manager/package.json @@ -38,7 +38,8 @@ "build": "npm run clean && vite build" }, "files": [ - "dist" + "dist", + "llms.txt" ], "devDependencies": { "@types/react": "catalog:", diff --git a/packages/url-param-compressor/llms.txt b/packages/url-param-compressor/llms.txt new file mode 100644 index 0000000..b647049 --- /dev/null +++ b/packages/url-param-compressor/llms.txt @@ -0,0 +1,47 @@ +# @naverpay/url-param-compressor + +> Compresses URL query parameters using deflate (fflate) + URL-safe base64 encoding. Works in both Node.js and browser environments. + +## Installation + +```bash +npm install @naverpay/url-param-compressor +``` + +## Usage + +```ts +import { URLParamCompressor } from '@naverpay/url-param-compressor' + +const compressor = new URLParamCompressor({ cacheCapacity: 100, debug: false }) + +// Compress: Record → string +const { result, isCompressed } = compressor.compress({ userId: '123', tab: 'history' }) + +// Decompress: string → Record | null +const params = compressor.decompress(result) + +// Get single key (uses LRU cache to avoid re-decompressing) +const userId = compressor.get(result, 'userId') +``` + +## Constructor Options + +```ts +new URLParamCompressor({ + cacheCapacity?: number // LRU cache size for decompress results (default: 100) + debug?: boolean // logs compression ratio or skip reason to console + deflateOptions?: { + level?: 0-9 // compression level (default: 6) + mem?: number // memory level + dictionary?: Uint8Array // preset dictionary for domain-specific compression + } +}) +``` + +## Behavior + +- `compress` always returns a result. If the compressed form is larger than the original, it returns the raw `URLSearchParams` string and sets `isCompressed: false`. +- `decompress` returns `null` on failure (malformed input) instead of throwing. +- URL-safe base64: replaces `+` with `-`, `/` with `_`, strips trailing `=`. +- In Node.js, uses `Buffer`; in browser, uses `btoa`/`atob`. diff --git a/packages/url-param-compressor/package.json b/packages/url-param-compressor/package.json index d964652..63a3de3 100644 --- a/packages/url-param-compressor/package.json +++ b/packages/url-param-compressor/package.json @@ -34,7 +34,8 @@ "compressor" ], "files": [ - "dist" + "dist", + "llms.txt" ], "scripts": { "clean": "rm -rf dist", diff --git a/packages/utils/llms.txt b/packages/utils/llms.txt new file mode 100644 index 0000000..4d5bf03 --- /dev/null +++ b/packages/utils/llms.txt @@ -0,0 +1,62 @@ +# @naverpay/utils + +> JavaScript/TypeScript utility library for Naver Financial frontend teams. Provides formatting, masking, Korean language helpers, validation, async utilities, and more. + +## Installation + +```bash +npm install @naverpay/utils +``` + +## API + +### Number / String Formatting + +- `formatNumberWithComma(value)` — adds thousand separators (e.g. `1234567` → `"1,234,567"`) +- `formatTenThousandUnitsAmount(value)` — Korean 만(萬) unit formatting +- `createNumberFormatter(options)` — factory for locale-aware Intl.NumberFormat wrappers +- `formatKoreanPhoneNumber(digits)` — formats raw digits to `010-XXXX-XXXX` +- `formatBusinessRegistrationNumber(digits)` — formats to `XXX-XX-XXXXX` + +### Masking + +- `maskString(str, options)` — generic masking with configurable keep/mask ranges +- `maskEmail(email)` — masks the local part of an email +- `maskPhoneNumber(phone)` — masks middle digits of a phone number +- `maskAccountNumber(account)` — masks middle digits of a bank account number +- `maskCardNumber(card)` — masks middle digits of a card number +- `maskPassportNumber(passport)` — masks middle characters of a passport number + +### Korean Language + +- `get조사(word, 은는 | 이가 | 을를 | 으로로 | 와과)` — returns correct Korean postposition for a word +- `with조사(word, postposition)` — returns word + correct postposition +- `getKoreanWithSuffix(word, suffix)` — appends Korean suffix based on final consonant +- `마지막_문자_받침_여부(char)` — checks if last character has a final consonant (받침) +- `한글_여부(char)` — checks if a character is Korean (Hangul) +- `disassemble문자(str)` — decomposes Korean characters into individual jamo + +### Validation + +- `isValidKoreanPhoneNumber(phone)` — validates Korean phone number format +- `isValidBusinessRegistrationNumber(brn)` — validates Korean business registration number checksum + +### Async / Performance + +- `debounce(fn, wait)` — debounces a function +- `throttle(fn, wait)` — throttles a function +- `sleep(ms)` — returns a Promise that resolves after `ms` milliseconds +- `DeferredPromise` — a Promise with externally accessible `resolve` and `reject` + +### Misc + +- `isEmpty(value)` — returns `true` for `null`, `undefined`, `""`, `[]`, `{}` +- `deepMerge(target, ...sources)` — deep merges plain objects +- `createKeyValuePairObject(keys, values)` — creates a typed key-value pair object +- `createSeededRandom(seed)` — deterministic pseudo-random number generator (mulberry32) +- `getSecureMathRandom()` — `crypto.getRandomValues`-based replacement for `Math.random` +- `generateRandomString(length?)` — generates a random alphanumeric string +- `getRandomNumber(min, max)` — returns a random integer in [min, max] +- `encodeHTMLEntity(str)` — encodes `<`, `>`, `&`, `"`, `'` to HTML entities +- `replaceNoBreakSpace(str)` — replaces non-breaking spaces (`\u00A0`) with regular spaces +- `backOrClose()` — calls `history.back()` or `window.close()` depending on history length diff --git a/packages/utils/package.json b/packages/utils/package.json index 80393c3..a7885f8 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -44,6 +44,7 @@ "vitest": "^3.1.1" }, "files": [ - "dist" + "dist", + "llms.txt" ] } diff --git a/packages/vanilla-store/llms.txt b/packages/vanilla-store/llms.txt new file mode 100644 index 0000000..a69c57f --- /dev/null +++ b/packages/vanilla-store/llms.txt @@ -0,0 +1,67 @@ +# @naverpay/vanilla-store + +> Framework-agnostic state management library with optional React bindings, SSR safety, and localStorage/sessionStorage persistence. + +## Installation + +```bash +npm install @naverpay/vanilla-store +``` + +## Core Concepts + +A store is created with `createVanillaStore`. It holds state, supports subscriptions, and integrates with React via `useSyncExternalStore`. On the server (`typeof window === 'undefined'`), `set` is a no-op that logs an error — the store is read-only. + +## API + +### Store + +```ts +const store = createVanillaStore(initialState, equalityFn?, options?) + +store.get() // returns current state +store.set(next) // sets state; accepts value or updater fn (prev) => next +store.subscribe(cb) // subscribes to changes; returns unsubscribe fn +``` + +Equality defaults to shallow comparison. Pass a custom `equalityFn` as the second argument. + +### React Hooks + +```ts +// Full access — returns [value, set] +const [value, set] = useStore(store, initialValue?) + +// Read-only +const value = useGetStore(store, initialValue?) + +// Write-only +const set = useSetStore(store, initialValue?) + +// Selector — returns [selectedValue, set] +const [selected, set] = useStoreSelector(store, selector, { initialStoreValue?, isEqual? }) +``` + +### Derived Store (read-only) + +```ts +const derived = createVanillaSelect(store, (state) => state.someField) +// Use with the same hooks; set is typed as `never` +``` + +### Persistence + +```ts +import { LocalStoragePersist, SessionStoragePersist } from '@naverpay/vanilla-store' + +const store = createVanillaStore(initialState, undefined, { + persist: new LocalStoragePersist('my-key', initialState, (v): v is MyType => true), +}) +``` + +`Persistent` requires a `typeAssertion` guard to validate deserialized values before applying them. + +## Notes + +- Calling `set` on the server logs a console error and returns `initialState` — it does not throw. +- `useStoreSelector` uses a ref-based comparison to skip re-renders when the selected value is unchanged. diff --git a/packages/vanilla-store/package.json b/packages/vanilla-store/package.json index 541d726..6534b0d 100644 --- a/packages/vanilla-store/package.json +++ b/packages/vanilla-store/package.json @@ -52,6 +52,7 @@ "react": "catalog:" }, "files": [ - "dist" + "dist", + "llms.txt" ] } From ab4c2d8c61bb6838b9251c2595e774d5b02d5727 Mon Sep 17 00:00:00 2001 From: yujeong-jeon Date: Mon, 11 May 2026 15:43:51 +0900 Subject: [PATCH 3/3] =?UTF-8?q?:wrench:=20chore:=20changeset=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(llms.txt=20patch)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/brave-rivers-glow.md | 7 +++++++ .changeset/bright-meadows-fall.md | 7 +++++++ .changeset/fluffy-wolves-dance.md | 7 +++++++ .changeset/golden-clouds-rest.md | 7 +++++++ .changeset/sunny-hawks-jump.md | 7 +++++++ .changeset/swift-tigers-bloom.md | 7 +++++++ 6 files changed, 42 insertions(+) create mode 100644 .changeset/brave-rivers-glow.md create mode 100644 .changeset/bright-meadows-fall.md create mode 100644 .changeset/fluffy-wolves-dance.md create mode 100644 .changeset/golden-clouds-rest.md create mode 100644 .changeset/sunny-hawks-jump.md create mode 100644 .changeset/swift-tigers-bloom.md diff --git a/.changeset/brave-rivers-glow.md b/.changeset/brave-rivers-glow.md new file mode 100644 index 0000000..4718777 --- /dev/null +++ b/.changeset/brave-rivers-glow.md @@ -0,0 +1,7 @@ +--- +"@naverpay/url-param-compressor": patch +--- + +llms.txt 추가 + +- npm 배포 결과물에 `llms.txt` 포함 (`files` 배열 업데이트) diff --git a/.changeset/bright-meadows-fall.md b/.changeset/bright-meadows-fall.md new file mode 100644 index 0000000..69aabc1 --- /dev/null +++ b/.changeset/bright-meadows-fall.md @@ -0,0 +1,7 @@ +--- +"@naverpay/es-http-status-codes": patch +--- + +llms.txt 추가 + +- npm 배포 결과물에 `llms.txt` 포함 (`files` 배열 업데이트) diff --git a/.changeset/fluffy-wolves-dance.md b/.changeset/fluffy-wolves-dance.md new file mode 100644 index 0000000..f1ef055 --- /dev/null +++ b/.changeset/fluffy-wolves-dance.md @@ -0,0 +1,7 @@ +--- +"@naverpay/utils": patch +--- + +llms.txt 추가 + +- npm 배포 결과물에 `llms.txt` 포함 (`files` 배열 업데이트) diff --git a/.changeset/golden-clouds-rest.md b/.changeset/golden-clouds-rest.md new file mode 100644 index 0000000..678af10 --- /dev/null +++ b/.changeset/golden-clouds-rest.md @@ -0,0 +1,7 @@ +--- +"@naverpay/react-pdf": patch +--- + +llms.txt 추가 + +- npm 배포 결과물에 `llms.txt` 포함 (`files` 배열 업데이트) diff --git a/.changeset/sunny-hawks-jump.md b/.changeset/sunny-hawks-jump.md new file mode 100644 index 0000000..3cadff3 --- /dev/null +++ b/.changeset/sunny-hawks-jump.md @@ -0,0 +1,7 @@ +--- +"@naverpay/vanilla-store": patch +--- + +llms.txt 추가 + +- npm 배포 결과물에 `llms.txt` 포함 (`files` 배열 업데이트) diff --git a/.changeset/swift-tigers-bloom.md b/.changeset/swift-tigers-bloom.md new file mode 100644 index 0000000..1c26997 --- /dev/null +++ b/.changeset/swift-tigers-bloom.md @@ -0,0 +1,7 @@ +--- +"@naverpay/svg-manager": patch +--- + +llms.txt 추가 + +- npm 배포 결과물에 `llms.txt` 포함 (`files` 배열 업데이트)