
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
polychat-bridge
Advanced tools
YouTube, Chzzk, SOOP 등 서로 다른 인터넷 방송 플랫폼의 채팅 스트림을 하나의 공통 인터페이스로 다루는 TypeScript 라이브러리입니다. 플랫폼별 인증·전송 방식(REST 폴링, WebSocket, SDK 콜백)을 어댑터 패턴으로 캡슐화하여, 앱에서는 동일한 타입과 이벤트로 메시지를 처리합니다.
YouTube, Chzzk, SOOP 등 서로 다른 인터넷 방송 플랫폼의 채팅 스트림을 하나의 공통 인터페이스로 다루는 TypeScript 라이브러리입니다.
플랫폼별 인증·전송 방식(REST 폴링, WebSocket, SDK 콜백)을 어댑터 패턴으로 캡슐화하여, 앱에서는 동일한 타입과 이벤트로 메시지를 처리합니다.
npm install polychat-bridge
또는 yarn 사용:
yarn add polychat-bridge
각 플랫폼에서 OAuth 클라이언트를 생성해야 합니다:
http://localhost:3000/callback)http://localhost:3000/callback)http://localhost:3000/callback)http://localhost:3000 추가npm run build
npm run demo
데모 앱은 http://localhost:3000에서 실행됩니다.
CHZZK는 OAuth 2.0 인증을 사용하며, WebSocket을 통해 실시간 채팅 메시지를 수신합니다. https://developers.chzzk.naver.com 에서 클라이언트 ID / 클라이언트 Secret / 로그인 리디렉션 URL을 발급받으세요.
필수 정보:
clientId: CHZZK OAuth 클라이언트 IDclientSecret: CHZZK OAuth 클라이언트 SecretredirectUri: OAuth 콜백 URL (예: http://localhost:3000/callback)SOOP는 OAuth 인증과 자체 Chat SDK를 사용합니다. 사용
필수 정보:
clientId: SOOP OAuth 클라이언트 IDclientSecret: SOOP OAuth 클라이언트 SecretredirectUri: OAuth 콜백 URL (예: http://localhost:3000/callback)YouTube는 OAuth 2.0 Implicit Grant Flow를 사용하며, REST API 폴링 방식으로 채팅을 수신합니다.
필수 정보:
clientId: Google OAuth 클라이언트 IDredirectUri: OAuth 콜백 URL (예: http://localhost:3000/callback)데모 앱의 경우 apps/example-react/.env 파일을 생성:
# CHZZK
VITE_CHZZK_CLIENT_ID=your_chzzk_client_id
VITE_CHZZK_CLIENT_SECRET=your_chzzk_client_secret
# SOOP
VITE_SOOP_CLIENT_ID=your_soop_client_id
VITE_SOOP_CLIENT_SECRET=your_soop_client_secret
# YouTube
VITE_YOUTUBE_CLIENT_ID=your_youtube_client_id
모든 플랫폼의 채팅 메시지는 공통 ChatMessage 인터페이스로 통합됩니다:
interface ChatMessage {
platform: string; // 플랫폼 이름 ('chzzk', 'soop', 'youtube')
chat_id: string; // 메시지 고유 ID (v1.1.0에서 구현 예정)
nickname: string; // 사용자 닉네임
content: string; // 메시지 내용
timestamp: Date; // 메시지 전송 시간
}
예시:
{
platform: 'chzzk',
chat_id: 'unknown', // v1.1.0에서 고유 ID 지원 예정
nickname: 'user123',
content: '안녕하세요!',
timestamp: new Date('2025-10-14T12:00:00Z')
}
주의사항:
chat_id는 모든 플랫폼에서 'unknown'으로 반환됩니다각 어댑터의 init() 메서드는 OAuth 인증을 시작하고 필요한 리소스를 초기화합니다.
import { ChzzkAdapter } from 'polychat-bridge';
const adapter = new ChzzkAdapter();
await adapter.init({
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
redirectUri: 'YOUR_REDIRECT_URI'
});
import { SoopAdapter } from 'polychat-bridge';
const adapter = new SoopAdapter();
await adapter.init({
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET'
});
import { YouTubeAdapter } from 'polychat-bridge';
const adapter = new YouTubeAdapter();
await adapter.init({
clientId: 'YOUR_CLIENT_ID',
redirectUri: 'YOUR_REDIRECT_URI',
pollingIntervalSeconds: 5 // 선택사항: 1~10초, 기본값 5초
});
Polling 간격 설정:
pollingIntervalSeconds: YouTube API 폴링 주기 (1~10초)init() 후 authenticate()를 호출하여 액세스 토큰을 발급받습니다.
await adapter.authenticate({
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
redirectUri: 'YOUR_REDIRECT_URI',
state: '' // 사용하지 않으면 adapter 내부 state가 자동으로 사용됨
});
await adapter.authenticate({
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET'
});
await adapter.authenticate({});
// YouTube는 init()에서 이미 토큰을 획득했으므로 빈 객체 전달
인증 후 connect()를 호출하여 실제 채팅 스트림에 연결합니다.
// 이벤트 리스너 등록
adapter.on('message', (message: ChatMessage) => {
console.log('새 메시지:', message);
});
adapter.on('connected', () => {
console.log('연결 성공!');
});
adapter.on('error', (error: Error) => {
console.error('에러 발생:', error);
});
// 연결
await adapter.connect();
채팅 연결을 종료합니다.
await adapter.disconnect();
PolyChat을 사용한 통합 이벤트 처리
PolyChat은 모든 플랫폼의 어댑터 이벤트를 하나의 인터페이스로 통합합니다. 각 이벤트는 어떤 플랫폼에서 발생했는지 platform 정보를 포함합니다.
import { PolyChat, ChzzkAdapter, SoopAdapter } from 'polychat-bridge';
// PolyChat 인스턴스 생성
const polyChat = new PolyChat();
// 어댑터 등록
const chzzkAdapter = new ChzzkAdapter();
const soopAdapter = new SoopAdapter();
polyChat.registerAdapter(chzzkAdapter);
polyChat.registerAdapter(soopAdapter);
// 통합 이벤트 리스너 등록
polyChat.on('message', ({ platform, message }) => {
console.log(`[${platform}] ${message.nickname}: ${message.content}`);
});
polyChat.on('connected', ({ platform }) => {
console.log(`[${platform}] 연결됨`);
});
polyChat.on('error', ({ platform, error }) => {
console.error(`[${platform}] 에러:`, error.message);
});
어댑터 초기화가 완료되었을 때 발생합니다.
polyChat.on('initialized', ({ platform }) => {
console.log(`[${platform}] 초기화 완료`);
});
이벤트 데이터:
platform: string - 플랫폼 이름 ('chzzk', 'soop', 'youtube')화면 표시: "🚀 초기화가 완료되었습니다" (파란색 시스템 메시지)
채팅 메시지를 수신했을 때 발생합니다.
polyChat.on('message', ({ platform, message }) => {
console.log(`[${platform}] ${message.nickname}: ${message.content}`);
});
이벤트 데이터:
platform: string - 플랫폼 이름message: ChatMessage - 채팅 메시지 객체
platform: string - 플랫폼 이름chat_id: string - 메시지 ID (현재 'unknown')nickname: string - 사용자 닉네임content: string - 메시지 내용timestamp: Date - 메시지 시간화면 표시: 일반 채팅 메시지로 표시 (흰색 배경)
채팅 서버에 연결되었을 때 발생합니다.
polyChat.on('connected', ({ platform }) => {
console.log(`[${platform}] 채팅 서버 연결 완료`);
});
이벤트 데이터:
platform: string - 플랫폼 이름화면 표시: "✅ 채팅 서버에 연결되었습니다" (파란색 시스템 메시지)
채팅 서버와의 연결이 끊어졌을 때 발생합니다.
polyChat.on('disconnected', ({ platform }) => {
console.log(`[${platform}] 채팅 서버 연결 해제`);
});
이벤트 데이터:
platform: string - 플랫폼 이름화면 표시: "⚠️ 채팅 서버 연결이 해제되었습니다" (파란색 시스템 메시지)
인증 상태가 변경되었을 때 발생합니다.
polyChat.on('auth', ({ platform, isAuthenticated }) => {
console.log(`[${platform}] 인증 상태:`, isAuthenticated ? '성공' : '실패');
});
이벤트 데이터:
platform: string - 플랫폼 이름isAuthenticated: boolean - 인증 성공 여부화면 표시:
에러가 발생했을 때 발생합니다.
polyChat.on('error', ({ platform, error }) => {
console.error(`[${platform}] 에러:`, error.message);
});
이벤트 데이터:
platform: string - 플랫폼 이름error: Error - 에러 객체화면 표시: "❌ 오류 발생: [에러 메시지]" (파란색 시스템 메시지)
const handleMessage = ({ platform, message }) => {
console.log(`[${platform}] 메시지:`, message.content);
};
// 리스너 등록
polyChat.on('message', handleMessage);
// 리스너 제거
polyChat.off('message', handleMessage);
import { PolyChat, ChzzkAdapter, SoopAdapter, YouTubeAdapter } from 'polychat-bridge';
const polyChat = new PolyChat();
// 어댑터 생성 및 등록
const chzzk = new ChzzkAdapter();
const soop = new SoopAdapter();
const youtube = new YouTubeAdapter();
polyChat.registerAdapter(chzzk);
polyChat.registerAdapter(soop);
polyChat.registerAdapter(youtube);
// 통합 이벤트 리스너
polyChat.on('initialized', ({ platform }) => {
console.log(`✅ ${platform} 초기화 완료`);
});
polyChat.on('auth', ({ platform, isAuthenticated }) => {
console.log(`🔑 ${platform} 인증: ${isAuthenticated ? '성공' : '실패'}`);
});
polyChat.on('connected', ({ platform }) => {
console.log(`🔗 ${platform} 연결됨`);
});
polyChat.on('message', ({ platform, message }) => {
console.log(`💬 [${platform}] ${message.nickname}: ${message.content}`);
});
polyChat.on('error', ({ platform, error }) => {
console.error(`❌ ${platform} 에러:`, error.message);
});
polyChat.on('disconnected', ({ platform }) => {
console.log(`⚠️ ${platform} 연결 해제`);
});
// 초기화
await chzzk.init({ clientId: '...', clientSecret: '...', redirectUri: '...' });
await soop.init({ clientId: '...', clientSecret: '...' });
await youtube.init({ clientId: '...', redirectUri: '...', pollingIntervalSeconds: 5 });
// 인증
await chzzk.authenticate({ clientId: '...', clientSecret: '...', redirectUri: '...', state: '' });
await soop.authenticate({ clientId: '...', clientSecret: '...' });
await youtube.authenticate({});
// 연결
await chzzk.connect();
await soop.connect();
await youtube.connect();
// 모든 어댑터 연결 해제
await polyChat.disconnectAll();
브라우저 개발자 도구의 Console 탭에서 다음 로그를 확인할 수 있습니다:
개발 모드 (NODE_ENV !== 'production'):
[PLATFORM] OAuth code received - OAuth 인증 완료[PLATFORM] Authenticated successfully - 토큰 발급 완료[PLATFORM] Connected - 채팅 서버 연결[PLATFORM] Disconnected - 연결 해제[HTTP] → GET/POST ... - HTTP 요청[HTTP] ← 200 ... - HTTP 응답배포 모드 (NODE_ENV === 'production'):
[PLATFORM] Token/session revoked - 세션 만료[HTTP] ⨯ 4xx/5xx ... - HTTP 에러로그 레벨:
debug: 개발 전용 (상세 디버깅 정보)info: 개발 전용 (일반 정보)warn: 항상 출력 (경고 메시지)error: 항상 출력 (에러 메시지)MIT
FAQs
YouTube, Chzzk, SOOP 등 서로 다른 인터넷 방송 플랫폼의 채팅 스트림을 하나의 공통 인터페이스로 다루는 TypeScript 라이브러리입니다. 플랫폼별 인증·전송 방식(REST 폴링, WebSocket, SDK 콜백)을 어댑터 패턴으로 캡슐화하여, 앱에서는 동일한 타입과 이벤트로 메시지를 처리합니다.
The npm package polychat-bridge receives a total of 1 weekly downloads. As such, polychat-bridge popularity was classified as not popular.
We found that polychat-bridge demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.