Files
2026-09-16 17:22:14 +09:00

43 lines
2.2 KiB
Markdown

# Contract: 프론트 데이터 인터페이스 (`snippets.api.ts`)
feature의 유일한 데이터 진입점. 화면·hook은 이 인터페이스만 알고, 뒤가 브릿지(SQLite)인지 나중에 백엔드인지는 모른다. (spec FR-022 / plan 편차1: HTTP 클라이언트 미경유)
```ts
import type { Snippet, SnippetInput } from "../types"
export interface SnippetsApi {
list(): Promise<Snippet[]> // usage 병합, 정렬은 프론트가
create(input: SnippetInput): Promise<Snippet> // 중복 name → reject(Error)
update(input: SnippetInput): Promise<Snippet> // name=키
remove(name: string): Promise<void>
recordUse(name: string): Promise<{ name: string; usageCount: number; lastUsed: number }> // 붙여넣기 성공 후, 갱신된 usage 반환(caller는 무시 가능)
}
```
- v1 구현체 `snippetBridge`(브릿지 왕복). 나중에 백엔드 전환 시 이 인터페이스 뒤 구현만 교체.
- 반환 타입은 순수 데이터(브릿지/HTTP 세부 노출 안 함). 실패는 `Error` reject.
## react-query 계약 (`hooks/useSnippets.ts`) — memos 패턴 준용
```ts
export const SNIPPETS_KEY = "snippets"
useSnippets() // useQuery([SNIPPETS_KEY]) → Snippet[]
useCreateSnippet() // mutation → invalidate([SNIPPETS_KEY]) + sonner "스니펫 생성됨"
useUpdateSnippet() // → invalidate + "저장됨"
useDeleteSnippet() // → invalidate + "삭제됨"
useRecordUse() // → invalidate([SNIPPETS_KEY]) (랭킹 갱신). 토스트 없음(조용히)
```
- 에러: 브릿지 실패는 `ApiError`(HTTP 전용)가 아니라 rejected promise의 순수 `Error`임 → `err instanceof Error ? err.message : "<한글 폴백>"` 형태(memos 톤은 같되 타입만 Error).
- `useSnippets`가 준 목록에 `core/search`+`core/ranking`을 화면에서 적용(서버 정렬 아님 — 로컬 계산).
## 붙여넣기 (기존 재사용, 신규 아님)
```ts
import { pasteToApp } from "@/lib/bridge/webviewBridge"
// Enter / Alt+숫자 →
pasteToApp(snippet.body) // 기존 paste.code — C# PasteService가 앞 창에 Ctrl+V + 창 숨김
await recordUse(snippet.name)
```