Public Source Viewer
비나래아카이브 개발자 포털
실제 서비스 구조를 살펴볼 수 있는 공개용 코드 뷰어입니다. 인증, 세션, 외부 연동, 토큰, 관리자 식별 등 보안상 민감한 구현은 파일 단위 또는 줄 단위로 검열됩니다.
src/services/home.service.ts
공개 가능
1
import fs from 'fs/promises';
2
import path from 'path';
3
import sanitizeHtml from 'sanitize-html';
4
[SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
5
import { decodeHtmlEntities } from './blog.service';
6
7
export type HomeEntry = {
8
title: string;
9
excerpt: string;
10
category: '아카이브' | '블로그';
11
date: string;
12
url: string;
13
};
14
15
function plain(value: unknown): string {
16
return decodeHtmlEntities(sanitizeHtml(String(value || ''), {
17
allowedTags: [],
18
allowedAttributes: {},
19
nonTextTags: ['script', 'style', 'textarea', 'noscript']
20
})).replace(/\s+/g, ' ').trim();
21
}
22
23
async function readEntries(file: string, library: boolean): Promise<HomeEntry[]> {
24
try {
25
[SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
26
if (!Array.isArray(data)) return [];
27
return data.filter(post => post && !post.isPrivate
28
&& ['string', 'number'].includes(typeof post.id) && String(post.id).trim()).map(post => {
29
const excerpt = plain(post.content);
30
const timestamp = Date.parse(library ? post.createdAt : post.timestamp);
31
return {
32
title: plain(post.title).slice(0, 100) || excerpt.slice(0, 56) || '제목 없는 기록',
33
excerpt: excerpt.slice(0, 140),
34
category: library ? '블로그' as const : '아카이브' as const,
35
date: Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : '',
36
url: library ? `/hinana/post/${encodeURIComponent(String(post.id))}`
37
: `/hinana/index?selectedId=${encodeURIComponent(String(post.id))}`
38
};
39
});
40
} catch {
41
// Missing or damaged data must not make the entry page unavailable.
42
return [];
43
}
44
}
45
46
export async function getHomeEntries(): Promise<HomeEntry[]> {
47
let files: string[];
48
[SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
49
[SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
50
const entries = await Promise.all(sources.map(file => readEntries(file, file !== 'posts.json')));
51
return entries.flat().sort((a, b) => (Date.parse(b.date) || 0) - (Date.parse(a.date) || 0)).slice(0, 3);
52
}
53