feat(release): prepare 1.1.0 candidate

This commit is contained in:
Yun Chan 2026-08-29 18:33:45 +09:00
parent 5a34f66981
commit 5205dcdfa9
736 changed files with 115667 additions and 12203 deletions

View file

@ -0,0 +1,102 @@
export interface GenerateMeetingDocumentRequest {
meetingId: string
templateId: string
idempotencyKey: string
title: string
model: 'claude-haiku-4-5-20251001' | 'claude-sonnet-4-6' | 'claude-opus-4-6'
}
export interface ProviderDocumentResult {
content: string
inputTokens: number | null
outputTokens: number | null
}
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
const MODELS = new Set<GenerateMeetingDocumentRequest['model']>([
'claude-haiku-4-5-20251001',
'claude-sonnet-4-6',
'claude-opus-4-6',
])
const REQUEST_KEYS = new Set([
'meetingId',
'templateId',
'idempotencyKey',
'title',
'model',
])
export class MeetingDocumentRequestError extends Error {
readonly status = 400
constructor(message: string) {
super(message)
this.name = 'MeetingDocumentRequestError'
}
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
function requireUuid(value: unknown, field: string): string {
if (typeof value !== 'string' || !UUID_PATTERN.test(value)) {
throw new MeetingDocumentRequestError(`${field} must be a UUID`)
}
return value.toLowerCase()
}
export function parseGenerateMeetingDocumentRequest(
value: unknown,
): GenerateMeetingDocumentRequest {
if (!isRecord(value)) throw new MeetingDocumentRequestError('Invalid JSON body')
const unsupported = Object.keys(value).filter((key) => !REQUEST_KEYS.has(key))
if (unsupported.length > 0) {
throw new MeetingDocumentRequestError('Unsupported request fields')
}
const title = typeof value.title === 'string'
? value.title.trim().replace(/\s+/g, ' ')
: ''
if (title.length < 1 || title.length > 160) {
throw new MeetingDocumentRequestError('title must contain 1-160 characters')
}
const model = value.model === undefined
? 'claude-haiku-4-5-20251001'
: value.model
if (typeof model !== 'string' || !MODELS.has(model as GenerateMeetingDocumentRequest['model'])) {
throw new MeetingDocumentRequestError('Unsupported model')
}
return {
meetingId: requireUuid(value.meetingId, 'meetingId'),
templateId: requireUuid(value.templateId, 'templateId'),
idempotencyKey: requireUuid(value.idempotencyKey, 'idempotencyKey'),
title,
model: model as GenerateMeetingDocumentRequest['model'],
}
}
function safeTokenCount(value: unknown): number | null {
return Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : null
}
export function parseProviderDocumentResult(value: unknown): ProviderDocumentResult | null {
if (!isRecord(value) || !Array.isArray(value.content)) return null
const text = value.content
.filter((block): block is Record<string, unknown> => isRecord(block))
.filter((block) => block.type === 'text' && typeof block.text === 'string')
.map((block) => (block.text as string).trim())
.filter((part) => part.length > 0)
.join('\n\n')
.trim()
if (text.length < 1 || text.length > 100000) return null
const usage = isRecord(value.usage) ? value.usage : {}
return {
content: text,
inputTokens: safeTokenCount(usage.input_tokens),
outputTokens: safeTokenCount(usage.output_tokens),
}
}