boat-editor-server
v0.1.0
Published
Server utilities for boat-editor: AI handlers, poll handlers, image upload
Downloads
104
Maintainers
Readme
boat-editor-server
boat-editor를 위한 서버 유틸리티. AI 핸들러, 이미지 업로드, Poll(투표) 핸들러를 제공합니다.
Installation
npm install boat-editor-serverAI Handler
Anthropic Claude, OpenAI, Google Gemini를 지원하는 AI 핸들러. 환경변수 기반으로 프로바이더를 자동 감지합니다.
Setup
# 하나만 설정하면 자동 감지 (우선순위: Anthropic > OpenAI > Gemini)
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
GEMINI_API_KEY=AI...Usage (Next.js App Router)
// app/api/ai/route.ts
import { createAIHandler } from 'boat-editor-server'
const handler = createAIHandler()
export async function POST(req: Request) {
return handler.handleRequest(req)
}Options
createAIHandler({
provider: 'anthropic', // 프로바이더 지정 (기본: 환경변수 자동 감지)
apiKey: 'sk-...', // API 키 (기본: 환경변수)
model: 'claude-sonnet-4-20250514', // 모델 지정 (기본: 프로바이더별 기본값)
})Features
| Feature | Description |
|---------|-------------|
| spellCheck | 선택 텍스트의 오탈자/문법 교정 |
| contextConnect | 커서 기준 앞뒤 문맥의 자연스러운 연결 |
| contentGenerate | 지시사항 기반 콘텐츠 생성 (SSE 스트리밍 지원) |
Image Upload Handler
Local Storage (개발용)
import { createImageUploadHandler } from 'boat-editor-server'
const handler = createImageUploadHandler({
storage: 'local',
uploadDir: './public/uploads',
publicPath: '/uploads',
})
export const POST = handlerCustom Storage (클라우드 연동)
import { createImageUploadHandler } from 'boat-editor-server'
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
const s3 = new S3Client({ /* ... */ })
const handler = createImageUploadHandler({
storage: 'custom',
customUploader: async (file, filename, mimeType) => {
await s3.send(new PutObjectCommand({
Bucket: 'my-bucket',
Key: `images/${filename}`,
Body: file,
ContentType: mimeType,
}))
return `https://cdn.example.com/images/${filename}`
},
})
export const POST = handlerOptions
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| storage | 'local' \| 'custom' | — | 스토리지 타입 (필수) |
| uploadDir | string | — | 로컬 저장 경로 (local일 때) |
| publicPath | string | — | 공개 URL 경로 (local일 때) |
| customUploader | (file, filename, mimeType) => Promise<string> | — | 커스텀 업로드 함수 (custom일 때) |
| maxFileSize | number | 10485760 (10MB) | 최대 파일 크기 (bytes) |
| allowedMimeTypes | string[] | ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] | 허용 MIME 타입 |
Poll Handlers
Prisma 기반 투표 CRUD 핸들러.
Prisma Schema
데이터베이스에 아래 모델을 추가하세요:
model BoatPoll {
id String @id @default(uuid())
title String
allowMultiple Boolean @default(false)
isAnonymous Boolean @default(false)
resultVisibility String @default("AFTER_VOTE")
endDate DateTime?
maxParticipants Int?
createdAt DateTime @default(now())
options BoatPollOption[]
votes BoatPollVote[]
@@map("boat_polls")
}
model BoatPollOption {
id String @id @default(uuid())
pollId String
text String
order Int @default(0)
poll BoatPoll @relation(fields: [pollId], references: [id])
votes BoatPollVote[]
@@map("boat_poll_options")
}
model BoatPollVote {
id String @id @default(uuid())
pollId String
optionId String
userId String
createdAt DateTime @default(now())
poll BoatPoll @relation(fields: [pollId], references: [id])
option BoatPollOption @relation(fields: [optionId], references: [id])
@@unique([pollId, userId, optionId])
@@map("boat_poll_votes")
}Usage (Next.js App Router)
// app/api/poll/[[...path]]/route.ts
import { createPollHandlers } from 'boat-editor-server'
import { prisma } from '@/lib/prisma'
const handlers = createPollHandlers({
prisma,
getCurrentUserId: async (req) => {
// 인증 로직에서 사용자 ID 반환
const session = await getSession(req)
return session?.user?.id ?? null
},
})
export async function GET(req: Request) {
return handlers.handleRequest(req)
}
export async function POST(req: Request) {
return handlers.handleRequest(req)
}API Endpoints
| Method | Path | Description |
|--------|------|-------------|
| POST | /api/poll | 투표 생성 |
| GET | /api/poll/:id | 투표 조회 |
| POST | /api/poll/:id/vote | 투표하기 |
| GET | /api/poll/:id/results | 결과 조회 |
Result Visibility
| Option | Description |
|--------|-------------|
| AFTER_VOTE | 투표 후 결과 공개 (기본값) |
| AFTER_END | 투표 종료 후 결과 공개 |
| ALWAYS | 항상 결과 공개 |
License
MIT
