Initial Commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# 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)
|
||||
```
|
||||
Reference in New Issue
Block a user