- 삭제: services/{lotto,prompt,automation,ai-kit,stock,tools} + api/{lotto,tools}
- 노출 제거: /freelance, /services/website (noindex + robots/sitemap 제외, 외부 지원서 링크 유지)
- 신규: /services/music (3-tier 39k/99k/149k, 4단계 프로세스)
- 신규: /services/blog (블로그 자동화 팩 29k 1회성)
- 신규: PurchaseAgreementModal (전자상거래법 17조 동의 + 계좌이체)
- 개편: 홈 대시보드 (음악 Hero + 사주/블로그팩/일반문의 서브카드)
- 사이드바 재구성, sitemap/robots/JSON-LD 갱신
- 환불정책 신규 상품 반영 + 법적 근거 명시
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
96 lines
3.2 KiB
TypeScript
96 lines
3.2 KiB
TypeScript
/**
|
|
* Telegram Bot API 유틸리티
|
|
* 환경변수: TELEGRAM_BOT_TOKEN
|
|
*/
|
|
|
|
const BASE = () => {
|
|
const token = process.env.TELEGRAM_BOT_TOKEN;
|
|
if (!token) throw new Error('TELEGRAM_BOT_TOKEN이 설정되지 않았습니다.');
|
|
return `https://api.telegram.org/bot${token}`;
|
|
};
|
|
|
|
// ─── 메시지 전송 ──────────────────────────────────────────────────────────────
|
|
|
|
export async function sendMessage(
|
|
chatId: string | number,
|
|
text: string,
|
|
options: { parse_mode?: 'Markdown' | 'HTML'; disable_web_page_preview?: boolean } = {}
|
|
): Promise<{ ok: boolean; description?: string }> {
|
|
const res = await fetch(`${BASE()}/sendMessage`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
chat_id: chatId,
|
|
text,
|
|
parse_mode: options.parse_mode ?? 'Markdown',
|
|
disable_web_page_preview: options.disable_web_page_preview ?? true,
|
|
}),
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
// ─── 로또 번호 알림 메시지 포맷 ──────────────────────────────────────────────
|
|
|
|
export function formatLottoMessage(
|
|
numbers: number[],
|
|
drawDate: string,
|
|
planName: string,
|
|
round?: number
|
|
): string {
|
|
const balls = numbers.map((n) => `*${String(n).padStart(2, '0')}*`).join(' ');
|
|
const roundText = round ? ` (제${round}회 예상)` : '';
|
|
|
|
return [
|
|
`🎰 *쟁승메이드 로또 번호 추천*${roundText}`,
|
|
`📅 ${drawDate} | ${planName}`,
|
|
``,
|
|
`${balls}`,
|
|
``,
|
|
`📊 합계: ${numbers.reduce((a, b) => a + b, 0)} | 홀수: ${numbers.filter((n) => n % 2 !== 0).length}개`,
|
|
``,
|
|
`⚠️ 통계 기반 추천이며 당첨을 보장하지 않습니다.`,
|
|
].join('\n');
|
|
}
|
|
|
|
// ─── 웹훅 등록 ───────────────────────────────────────────────────────────────
|
|
|
|
export async function setWebhook(
|
|
webhookUrl: string,
|
|
secretToken?: string
|
|
): Promise<{ ok: boolean; description?: string }> {
|
|
const body: Record<string, unknown> = {
|
|
url: webhookUrl,
|
|
allowed_updates: ['message'],
|
|
};
|
|
if (secretToken) body.secret_token = secretToken;
|
|
|
|
const res = await fetch(`${BASE()}/setWebhook`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
export async function getWebhookInfo(): Promise<{ ok: boolean; result?: { url: string; pending_update_count: number } }> {
|
|
const res = await fetch(`${BASE()}/getWebhookInfo`);
|
|
return res.json();
|
|
}
|
|
|
|
// ─── Telegram Update 타입 ─────────────────────────────────────────────────────
|
|
|
|
export interface TelegramUpdate {
|
|
update_id: number;
|
|
message?: {
|
|
message_id: number;
|
|
from?: {
|
|
id: number;
|
|
username?: string;
|
|
first_name?: string;
|
|
};
|
|
chat: { id: number; type: string };
|
|
text?: string;
|
|
date: number;
|
|
};
|
|
}
|