
언어 🇰🇷 한국어
Val Town 설치
Val Town 앱에 실시간 댓글 추가
Val Town 은 Deno에서 TypeScript를 실행하므로 val은 실제 서버입니다. 이는 FastComments에 적합합니다: 위젯은 페이지에 삽입되는 script 태그이며, Secure SSO나 웹훅 검증처럼 비밀이 필요한 모든 작업을 동일한 val에서 서버 측으로 실행할 수 있습니다.
이 가이드는 HTTP val에 댓글 위젯을 추가하고, 인덱스 페이지에 댓글 수를 표시하며, 사용자가 이미 가지고 있는 Val Town 계정으로 로그인하고, 댓글 웹훅을 받는 방법을 다룹니다.
시도하는 데 계정이 필요하지 않습니다. 예제는 tenantId: "demo" 를 사용하며, 공유 샌드박스이며, 2단계에서 자신의 것으로 전환하는 방법을 설명합니다.
1단계: 위젯 추가 
The widget is a script tag and a container element, so it drops into whatever your val already renders. This example uses Hono JSX, which is what Val Town's HTTP templates use.
Run 
배포 전에 urlId 선택하기
urlId는 댓글이 어느 스레드에 달릴지를 결정합니다. 이를 설정하지 않으면 현재 페이지 URL을 정리한 버전이 기본값으로 사용되는데, 이는 Val Town에서 변하는 바로 그 요소입니다: 서브도메인을 획득하기 전까지 val은 긴 *.web.val.run 호스트명을 가지고, 브랜치는 각각 고유한 URL을 가지며, 페이지 이름을 바꾸면 경로가 바뀝니다. 각 변형은 조용히 별도의 빈 스레드가 되며, 그 결과는 “내 댓글이 사라졌다”는 현상으로 나타납니다.
위와 같이 게시물 슬러그나 데이터베이스 ID와 같이 여러분이 제어할 수 있는 안정적인 값으로 설정하세요. 또한 url을 전달하면 알림 이메일 및 관리 도구가 실제 페이지로 연결될 수 있습니다.
JavaScript 없이 댓글 유지하기
FastComments는 전체 스레드를 서버 측에서 렌더링하므로, val은 이를 <noscript> 블록에 삽입할 수 있습니다:
Run 
매개변수를 URL 인코딩하세요. 서버 측 버전은 익명 및 로그인 댓글, SSO, 그리고 중첩 답글을 지원합니다.
2단계: 내 계정 사용 
tenantId: "demo"은 공유 퍼블릭 샌드박스입니다. 회원가입 없이도 작동하므로 예제에서 이를 사용하지만, FastComments를 시도하는 다른 모든 사용자는 동일한 스레드에 글을 쓰고 누구나 이를 관리할 수 있습니다. 중요한 내용을 게시하기 전에 전환하세요.
Your tenant ID is on the API secret page.
A tenant ID is public and belongs in browser code. An API secret does not, and nothing on this page needs one.
환경 변수에서 읽기
Val Town 값은 무료 티어에서 공개되어 있기 때문에 소스가 전 세계에서 읽을 수 있습니다. 민감한 정보는 환경 변수에 보관하고 Deno.env.get으로 읽으세요:
Run 
이는 Val Town에서 두 번째 이유 때문에 평소보다 더 중요합니다: val을 리믹스하면 환경 변수 키는 복사되지만 값은 복사되지 않습니다. 환경 변수에 보관된 비밀은 다른 사람의 계정으로 val이 이동할 때 따라가지 않습니다. 파일에 기록된 비밀은 따라갑니다.
"demo"로 되돌리면 자체 테넌트를 설정하기 전에 val을 리믹스하는 모든 사용자가 정상적으로 작동합니다.
EU 계정
계정, 데이터 및 키는 하나의 지역에 존재합니다. 귀하의 계정이 eu.fastcomments.com에서 생성된 경우 모든 위젯 구성에도 region: "eu"가 필요하며, 스크립트는 cdn-eu.fastcomments.com에서 로드됩니다. 그렇지 않으면 두 설정을 그대로 두세요.
인덱스 페이지의 댓글 수 
인덱스 페이지에서는 행마다 하나의 comment-count 위젯을 렌더링하지 마세요. 이는 게시물당 하나의 요청이 발생합니다. 전체 페이지에 대해 단일 요청으로 처리되는 bulk count를 사용하세요.
각 행에 해당 스레드가 사용하는 urlId를 표시하고, bulk 위젯을 한 번만 로드하세요:
Run 
스크립트는 페이지 내 모든 .fast-comments-count 요소를 찾아 해당 카운트를 채워 넣습니다.
data-fast-comments-url-id는 게시물의 댓글 위젯이 사용하는 urlId와 일치해야 합니다. 위젯이 슬러그를 사용한다면, 마커도 슬러그를 사용합니다. 일치하지 않을 경우 댓글이 있는 스레드에서도 0이 표시됩니다.
스크립트는 window.FastCommentsBulkCountConfig를 폴링하므로, 스크립트 태그 앞이나 뒤에 설정을 넣는 것이 중요하지 않습니다.
std/oauth를 사용한 보안 SSO 
If your val already knows who the visitor is, Secure SSO hands that identity to the widget so they never see a second login. There are no endpoints to build and nothing to call at runtime: you compute three values server-side and pass them in the widget config.
Val Town ships zero-config login with std/oauth, so the visitor can sign in with the Val Town account they already have. Swap that for whatever your app uses; the FastComments half does not change.
서버에서 페이로드 구축
The API secret signs the payload and must never reach browser code. Install the SDK from npm, which works on Val Town's Deno runtime as-is:
Run 
getPayload() returns { userDataJSONBase64, verificationHash, timestamp }. Those three values are all that reach the browser. The secret signs them and is then dropped, so nothing in the page lets a reader forge a different user.
위젯에 전달하기
Run 
oauthMiddleware adds GET /auth/login, GET /auth/callback and POST /auth/logout for you. Note that logout is a POST, while the widget navigates to logoutURL with a GET, so point logoutURL at a small route of your own that submits the POST.
When the visitor is logged out, pass sso with only a loginURL. The widget then shows a login prompt instead of an anonymous comment box.
발생할 수 있는 문제
timestamp is epoch milliseconds, must not be in the future, and must not be more than two days old. Generate it on the server in the same request that computes the hash. Generating it in the browser is the classic failure: the value differs from the one that was hashed and every comment is rejected.
Never set isAdmin or isModerator from the identity provider. Signing in with a Val Town account says nothing about who should moderate your site.
See the SSO 가이드 for the full field list, group-gated threads, and badges.
웹훅 수신 
A val은 자연스러운 웹훅 수신기입니다: 안정적인 URL을 가지고 있으며, 서명을 검증할 수 있고, SQLite와 블롭 스토리지를 내장하고 있습니다.
FastComments는 ${timestamp}.${body}에 계정의 API 비밀키로 서명하고 두 개의 헤더를 전송합니다:
Run 
이 메서드는 이벤트를 전달합니다: 생성되거나 업데이트된 댓글의 경우 PUT, 삭제된 경우 DELETE.
Run 
문제를 일으키는 두 가지
원시 바이트를 검증하세요. JSON을 파싱하고 다시 직렬화하면 키 순서와 공백이 바뀌어 해시가 달라지며, 그 결과 원인 없이 모든 전달이 실패합니다. 이것이 웹훅 수신기가 "그냥 작동하지 않는다"는 일반적인 이유입니다.
상수 시간으로 비교하세요. 서명에 대한 단순 === 연산은 일치한 바이트 수를 누출하게 되며, 이는 바이트를 하나씩 위조하는 데 충분합니다.
이벤트 처리
빠르게 응답하세요. FastComments는 2xx가 아닌 응답에 대해 재시도하며, 계속 실패하는 엔드포인트는 결국 자동으로 비활성화됩니다. 따라서 응답을 반환한 후에 실제 작업을 수행하고, 인라인으로 처리하지 마세요.
해당 작업을 댓글 ID에 대해 멱등하도록 만드세요. 재시도 시 새로운 타임스탬프로 다시 서명되며, 편집 및 삭제 시 동일한 댓글 ID가 다시 도착하므로 중복 제거를 위한 안정적인 기준이 없습니다.
예시 Vals 
Four public vals you can remix, each covering one piece of this guide.
Blog with comments (live) 은 각 게시물 아래에 스레드가 있고 인덱스에 전체 댓글 수가 표시되는 Markdown 블로그입니다. 리믹스하는 순간 바로 작동하며, 하나의 환경 변수가 여러분의 계정으로 연결됩니다.
SSO demo (live) 은 방문자를 Val Town 계정으로 로그인시키고 그 신원을 위젯에 전달하므로 두 번째 로그인이 필요하지 않습니다.
Webhook receiver (live) 은 모든 전달에 대해 HMAC 서명을 검증하고 이벤트를 SQLite에 저장합니다. 테스트 페이로드에 서명하고 자체에 전달하는 버튼이 있어 실제 웹훅을 설정하기 전에 검증이 성공하는 것을 확인할 수 있습니다.
Agent skills (live) 은 위젯, SSO, REST API, 모더레이션, Disqus에서 마이그레이션까지를 다루는 FastComments 에이전트 스킬 라이브러리입니다. 이를 리믹스하면 Val Town의 에이전트인 Townie가 skills/ 폴더에서 자동으로 스킬을 가져와, 채팅에 문서를 붙여넣지 않아도 에이전트가 댓글을 설정하는 방법을 알게 됩니다.
The same skills install anywhere else with npx skills add fastcomments/skills.
도메인 오류 
demo 테넌트를 끄면 위젯이 인증 오류로 로드되지 않을 수 있습니다. 이는 FastComments가 해당 도메인에서 귀하의 계정을 사용할 수 있도록 허용해야 함을 인식하지 못하기 때문입니다.
Val Town은 여기서 다시 살펴볼 가치가 있습니다. 왜냐하면 val은 하나 이상의 호스트명으로 접근할 수 있기 때문입니다:
- 모든 HTTP val은 긴 기본 엔드포인트
<org>--<id>.web.val.run를 가집니다. - 맞춤 서브도메인을 클레임하면
<name>.val.run이 추가됩니다. - 맞춤 도메인(custom domain)을 사용하면 세 번째가 추가됩니다.
- 브랜치는 자체 URL을 갖게 됩니다.