cime-sdk 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/cime-sdk.svg)](https://www.npmjs.com/package/cime-sdk)
4
4
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ ![npm](https://img.shields.io/npm/dt/cime-sdk)
6
7
 
7
8
  **ci.me API를 위한 TypeScript SDK**입니다.
8
9
  Node.js 환경만을 지원합니다.
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ var WebSocket__default = /*#__PURE__*/_interopDefault(WebSocket);
16
16
  // package.json
17
17
  var package_default = {
18
18
  name: "cime-sdk",
19
- version: "1.0.0",
19
+ version: "1.0.2",
20
20
  description: "A structural and object-oriented TypeScript SDK for ci.me API",
21
21
  main: "dist/index.js",
22
22
  module: "dist/index.mjs",
@@ -37,10 +37,17 @@ var package_default = {
37
37
  test: "vitest",
38
38
  typecheck: "tsc --noEmit"
39
39
  },
40
- keywords: ["cime", "sdk", "typescript"],
40
+ keywords: [
41
+ "cime",
42
+ "sdk",
43
+ "typescript"
44
+ ],
41
45
  author: "whitespaca",
42
46
  license: "MIT",
43
- repository: { type: "git", url: "https://github.com/whitespaca/cime-sdk" },
47
+ repository: {
48
+ type: "git",
49
+ url: "https://github.com/whitespaca/cime-sdk"
50
+ },
44
51
  type: "commonjs",
45
52
  dependencies: {
46
53
  axios: "^1.15.0",
@@ -166,7 +173,7 @@ var AuthAPI = class {
166
173
  */
167
174
  async get(code) {
168
175
  this.validateCredentials();
169
- const { data } = await this.http.post("/api/openapi/auth/v1/token", {
176
+ const { data } = await this.http.post("/auth/v1/token", {
170
177
  grantType: "authorization_code",
171
178
  clientId: this.config.clientId,
172
179
  clientSecret: this.config.clientSecret,
@@ -180,7 +187,7 @@ var AuthAPI = class {
180
187
  */
181
188
  async refresh(refreshToken) {
182
189
  this.validateCredentials();
183
- const { data } = await this.http.post("/api/openapi/auth/v1/token", {
190
+ const { data } = await this.http.post("/auth/v1/token", {
184
191
  grantType: "refresh_token",
185
192
  clientId: this.config.clientId,
186
193
  clientSecret: this.config.clientSecret,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../package.json","../src/utils/version.ts","../src/errors/CimeAPIError.ts","../src/utils/httpClient.ts","../src/api/auth.ts","../src/api/users.ts","../src/api/channels.ts","../src/api/live.ts","../src/api/chat.ts","../src/api/categories.ts","../src/api/restrict.ts","../src/api/sessions.ts","../src/ws/CimeEventClient.ts","../src/client.ts","../src/utils/chatUtils.ts","../src/index.ts"],"names":["axios","axiosRetry","EventEmitter","WebSocket"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"name\": \"cime-sdk\",\n \"version\": \"1.0.0\",\n \"description\": \"A structural and object-oriented TypeScript SDK for ci.me API\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\"\n ],\n \"exports\": {\n \".\": {\n \"require\": \"./dist/index.js\",\n \"import\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.ts\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"keywords\": [\"cime\", \"sdk\", \"typescript\"],\n \"author\": \"whitespaca\",\n \"license\": \"MIT\",\n \"repository\": {\"type\": \"git\", \"url\": \"https://github.com/whitespaca/cime-sdk\" },\n \"type\": \"commonjs\",\n \"dependencies\": {\n \"axios\": \"^1.15.0\",\n \"axios-retry\": \"^4.5.0\",\n \"ws\": \"^8.20.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.6.0\",\n \"@types/ws\": \"^8.18.1\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.2\",\n \"vitest\": \"^4.1.4\"\n }\n}\n","import axios from 'axios';\r\nimport pkg from '../../package.json';\r\n\r\n/**\r\n * 로컬 패키지의 현재 버전을 반환합니다.\r\n */\r\nexport function getVersion(): string {\r\n return pkg.version;\r\n}\r\n\r\n/**\r\n * npm 레지스트리와 비교하여 최신 버전이 있는지 확인하고 콘솔에 알립니다.\r\n * 백그라운드에서 비동기로 실행됩니다.\r\n */\r\nexport async function checkVersion(): Promise<void> {\r\n try {\r\n const localVersion = pkg.version;\r\n const packageName = pkg.name; // 'cime-sdk'\r\n\r\n const { data, status } = await axios.get(`https://registry.npmjs.org/${packageName}/latest`, {\r\n timeout: 3000,\r\n });\r\n\r\n if (status !== 200 || !data || !data.version) {\r\n return;\r\n }\r\n\r\n const remoteVersion = data.version;\r\n\r\n if (isNewerVersion(localVersion, remoteVersion)) {\r\n console.log(`\\n======================================================`);\r\n console.log(`🚀 [CIME SDK] 새로운 버전을 찾았습니다!`);\r\n console.log(`현재 버전: ${localVersion} -> 최신 버전: ${remoteVersion}`);\r\n console.log(`UPDATE: npm install ${packageName}@${remoteVersion}`);\r\n console.log(`======================================================\\n`);\r\n }\r\n } catch (error) {\r\n return;\r\n }\r\n}\r\n\r\n/**\r\n * 두 버전 문자열을 비교합니다.\r\n * @returns remote가 local보다 크면 true\r\n */\r\nfunction isNewerVersion(local: string, remote: string): boolean {\r\n const lParts = local.split('.').map(Number);\r\n const rParts = remote.split('.').map(Number);\r\n\r\n const maxLength = Math.max(lParts.length, rParts.length);\r\n\r\n for (let i = 0; i < maxLength; i++) {\r\n const l = lParts[i] || 0;\r\n const r = rParts[i] || 0;\r\n \r\n if (r > l) return true;\r\n if (r < l) return false;\r\n }\r\n \r\n return false; // 완전히 동일한 버전\r\n}","import { CimeErrorResponse } from '../types';\r\n\r\n/**\r\n * ci.me API 요청 중 발생하는 에러를 캡슐화한 커스텀 에러 클래스입니다.\r\n * HTTP 상태 코드와 API가 반환한 상세 메시지를 포함합니다.\r\n */\r\nexport class CimeAPIError extends Error {\r\n public readonly statusCode: number;\r\n\r\n /**\r\n * @param errorResponse - API 서버에서 반환한 에러 객체\r\n */\r\n constructor(errorResponse: CimeErrorResponse) {\r\n super(errorResponse.message);\r\n this.name = 'CimeAPIError';\r\n this.statusCode = errorResponse.statusCode;\r\n\r\n // TypeScript 환경에서 Custom Error 생성 시 prototype 체인을 수동으로 복구 (instanceof 정상 작동을 위함)\r\n Object.setPrototypeOf(this, CimeAPIError.prototype);\r\n }\r\n}","import axios, { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios';\r\nimport axiosRetry from 'axios-retry';\r\nimport { CimeAPIError } from '../errors/CimeAPIError';\r\nimport { CimeCommonResponse, CimeErrorResponse, CimeClientOptions } from '../types';\r\nimport { getVersion } from './version';\r\n\r\n/**\r\n * 인증 정보와 기본 설정이 포함된 Axios 클라이언트 인스턴스를 생성합니다.\r\n */\r\nexport function createHttpClient(options: CimeClientOptions): AxiosInstance {\r\n const client = axios.create({\r\n baseURL: 'https://ci.me/api/openapi',\r\n timeout: options.timeout || 10000,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'User-Agent': `CimeSDK/${getVersion()} (Node)`,\r\n },\r\n });\r\n\r\n client.interceptors.request.use((config: InternalAxiosRequestConfig) => {\r\n if (options.accessToken) {\r\n config.headers['Authorization'] = `Bearer ${options.accessToken}`;\r\n }\r\n if (options.clientId && options.clientSecret) {\r\n config.headers['Client-Id'] = options.clientId;\r\n config.headers['Client-Secret'] = options.clientSecret;\r\n }\r\n return config;\r\n });\r\n\r\n axiosRetry(client, {\r\n retries: options.retries ?? 3,\r\n retryDelay: axiosRetry.exponentialDelay,\r\n retryCondition: (error: AxiosError) => {\r\n return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 500;\r\n },\r\n });\r\n\r\n client.interceptors.response.use(\r\n (response: AxiosResponse<CimeCommonResponse>) => {\r\n return response.data.content as any;\r\n },\r\n (error: AxiosError<CimeErrorResponse>) => {\r\n if (error.response && error.response.data) {\r\n throw new CimeAPIError(error.response.data);\r\n }\r\n throw error;\r\n }\r\n );\r\n\r\n return client;\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeTokenResponse } from '../types/auth';\r\n\r\nexport class AuthAPI {\r\n constructor(\r\n private readonly http: AxiosInstance,\r\n private readonly config: { clientId?: string; clientSecret?: string }\r\n ) {}\r\n\r\n /**\r\n * Authorization Code를 사용하여 Access Token과 Refresh Token을 발급받습니다.\r\n * @param code Redirect URI로 전달받은 인가 코드\r\n */\r\n public async get(code: string): Promise<CimeTokenResponse> {\r\n this.validateCredentials();\r\n\r\n const { data } = await this.http.post<CimeTokenResponse>('/api/openapi/auth/v1/token', {\r\n grantType: 'authorization_code',\r\n clientId: this.config.clientId,\r\n clientSecret: this.config.clientSecret,\r\n code\r\n });\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Refresh Token을 사용하여 Access Token을 갱신합니다.\r\n * @param refreshToken 이전에 발급받은 리프레시 토큰\r\n */\r\n public async refresh(refreshToken: string): Promise<CimeTokenResponse> {\r\n this.validateCredentials();\r\n\r\n const { data } = await this.http.post<CimeTokenResponse>('/api/openapi/auth/v1/token', {\r\n grantType: 'refresh_token',\r\n clientId: this.config.clientId,\r\n clientSecret: this.config.clientSecret,\r\n refreshToken\r\n });\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * 내부 헬퍼: 토큰 발급 시 필요한 Client ID 및 Secret 유효성 검사 (Fail-fast)\r\n */\r\n private validateCredentials(): void {\r\n if (!this.config.clientId || !this.config.clientSecret) {\r\n throw new Error(\r\n '[Cime SDK] OAuth 토큰을 발급/갱신하려면 초기화 시 clientId와 clientSecret이 필요합니다.'\r\n );\r\n }\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeUser, CimeClientOptions } from '../types';\r\n\r\n/**\r\n * 사용자(User) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class UsersAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 현재 Access Token에 연결된 사용자의 채널 정보를 조회합니다.\r\n *\r\n * @requires Scope: `READ:USER`\r\n * @throws {CimeAPIError} Access Token이 없거나 만료되었을 때 (401), 또는 권한이 부족할 때 발생합니다.\r\n * @returns 사용자의 채널 상세 정보\r\n * * @example\r\n * ```typescript\r\n * const me = await client.users.get();\r\n * console.log(`안녕하세요, ${me.channelName}님!`);\r\n * ```\r\n */\r\n public async get(): Promise<CimeUser> {\r\n if (!this.options.scopes?.includes('READ:USER')) {\r\n throw new Error('[UsersAPI] \"READ:USER\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // 인터셉터에서 response.data.content를 바로 반환하므로 리턴 타입은 CimeUser가 됩니다.\r\n return this.httpClient.get<any, CimeUser>('/open/v1/users/me');\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeDataList,\r\n CimeChannelInfo,\r\n CimeFollower,\r\n CimeChannelFollowersParams,\r\n CimeSubscriber,\r\n CimeChannelSubscribersParams,\r\n CimeManager,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 채널(Channel) 관련 API를 담당하는 클래스입니다.\r\n * 채널 정보, 팔로워, 구독자, 관리자 목록 조회 기능을 제공합니다.\r\n */\r\nexport class ChannelsAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 채널 ID 목록으로 채널의 기본 정보를 조회합니다. (최대 20개)\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param channelIds - 조회할 채널 ID 문자열 또는 ID 문자열의 배열\r\n * @returns 채널 정보 목록\r\n * * @example\r\n * ```typescript\r\n * const { data } = await client.channels.getChannels(['12345', '67890']);\r\n * ```\r\n */\r\n public async getChannels(channelIds: string | string[]): Promise<CimeDataList<CimeChannelInfo>> {\r\n // 배열이 들어올 경우 쉼표로 구분된 문자열로 자동 변환하여 편의성을 높입니다.\r\n const parsedIds = Array.isArray(channelIds) ? channelIds.join(',') : channelIds;\r\n \r\n return this.httpClient.get<any, CimeDataList<CimeChannelInfo>>('/open/v1/channels', {\r\n params: { channelIds: parsedIds },\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 팔로워 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:CHANNEL`\r\n * @param params - 페이징 파라미터 (page, size)\r\n * @returns 팔로워 목록\r\n */\r\n public async getFollowers(params?: CimeChannelFollowersParams): Promise<CimeDataList<CimeFollower>> {\r\n if (!this.options.scopes?.includes('READ:CHANNEL')) {\r\n throw new Error('[ChannelsAPI] \"READ:CHANNEL\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeFollower>>('/open/v1/channels/followers', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 구독자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:SUBSCRIPTION`\r\n * @param params - 페이징 및 정렬 파라미터 (page, size, sort)\r\n * @returns 구독자 목록\r\n */\r\n public async getSubscribers(params?: CimeChannelSubscribersParams): Promise<CimeDataList<CimeSubscriber>> {\r\n if (!this.options.scopes?.includes('READ:SUBSCRIPTION')) {\r\n throw new Error('[ChannelsAPI] \"READ:SUBSCRIPTION\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeSubscriber>>('/open/v1/channels/subscribers', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 관리자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:CHANNEL`\r\n * @returns 관리자 목록\r\n */\r\n public async getManagers(): Promise<CimeDataList<CimeManager>> {\r\n if (!this.options.scopes?.includes('READ:CHANNEL')) {\r\n throw new Error('[ChannelsAPI] \"READ:CHANNEL\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeManager>>('/open/v1/channels/streaming-roles');\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeCursorList,\r\n CimeLive,\r\n CimeLivesParams,\r\n CimeLiveSetting,\r\n CimeUpdateLiveSettingParams,\r\n CimeStreamKey,\r\n CimeLiveStatus,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 라이브(Live) 및 스트리밍 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class LiveAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 현재 진행 중인 라이브 방송 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param params - 커서 기반 페이징 파라미터 (size, next)\r\n * @returns 라이브 목록과 다음 페이지 커서 정보\r\n */\r\n public async getLives(params?: CimeLivesParams): Promise<CimeCursorList<CimeLive>> {\r\n return this.httpClient.get<any, CimeCursorList<CimeLive>>('/open/v1/lives', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 라이브 설정을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_STREAM_SETTINGS`\r\n * @returns 라이브 설정 정보\r\n */\r\n public async getSettings(): Promise<CimeLiveSetting> {\r\n if (!this.options.scopes?.includes('READ:LIVE_STREAM_SETTINGS')) {\r\n throw new Error('[LiveAPI] \"READ:LIVE_STREAM_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeLiveSetting>('/open/v1/lives/setting');\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 라이브 설정을 변경합니다. (전달된 필드만 업데이트)\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_STREAM_SETTINGS`\r\n * @param params - 변경할 라이브 설정 데이터\r\n */\r\n public async updateSettings(params: CimeUpdateLiveSettingParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_STREAM_SETTINGS')) {\r\n throw new Error('[LiveAPI] \"WRITE:LIVE_STREAM_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.patch('/open/v1/lives/setting', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 스트림 키(Stream Key)를 조회합니다.\r\n * OBS 등 외부 방송 도구 연동 시 사용됩니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_STREAM_KEY`\r\n * @returns 스트림 키\r\n */\r\n public async getStreamKey(): Promise<CimeStreamKey> {\r\n if (!this.options.scopes?.includes('READ:LIVE_STREAM_KEY')) {\r\n throw new Error('[LiveAPI] \"READ:LIVE_STREAM_KEY\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeStreamKey>('/open/v1/streams/key');\r\n }\r\n\r\n /**\r\n * 특정 채널의 라이브 방송 여부와 상태를 확인합니다.\r\n * 이 API는 인증 없이 호출할 수 있는 완전 공개 API입니다.\r\n *\r\n * @requires Auth: 불필요\r\n * @param channelId - 상태를 조회할 채널의 ID\r\n * @returns 라이브 상태 정보\r\n */\r\n public async getLiveStatus(channelId: string): Promise<CimeLiveStatus> {\r\n // 주의: 이 엔드포인트는 /open/v1/ 접두사 없이 /v1/ 으로 시작합니다.\r\n return this.httpClient.get<any, CimeLiveStatus>(`/v1/${channelId}/live-status`);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeChatSettings,\r\n CimeUpdateChatSettingsParams,\r\n CimeSendChatMessageParams,\r\n CimeSendChatMessageResponse,\r\n CimeRegisterChatNoticeParams,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 라이브 채팅(Chat) 설정 및 메시지 전송 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class ChatAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 인증된 사용자 채널의 채팅 설정을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_CHAT_SETTINGS`\r\n * @returns 채팅 설정 정보\r\n */\r\n public async getSettings(): Promise<CimeChatSettings> {\r\n if (!this.options.scopes?.includes('READ:LIVE_CHAT_SETTINGS')) {\r\n throw new Error('[ChatAPI] \"READ:LIVE_CHAT_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeChatSettings>('/open/v1/chats/settings');\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 채팅 설정을 변경합니다. (전달된 필드만 업데이트)\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT_SETTINGS`\r\n * @param params - 변경할 채팅 설정 데이터\r\n */\r\n public async updateSettings(params: CimeUpdateChatSettingsParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT_SETTINGS')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.put('/open/v1/chats/settings', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널 라이브 채팅에 메시지를 전송합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT`\r\n * @param params - 전송할 메시지 정보 및 발신자 타입\r\n * @returns 전송된 메시지 ID\r\n */\r\n public async sendMessage(params: CimeSendChatMessageParams): Promise<CimeSendChatMessageResponse> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.post<any, CimeSendChatMessageResponse>('/open/v1/chats/send', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널 라이브 채팅에 공지사항을 등록합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT_NOTICE`\r\n * @param params - 등록할 공지 메시지 내용 또는 기존 메시지 ID\r\n * @throws {Error} 파라미터가 모두 누락된 경우 서버 요청 전 사전 차단합니다.\r\n */\r\n public async registerNotice(params: CimeRegisterChatNoticeParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT_NOTICE')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT_NOTICE\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // Fail-fast 로직: 서버로 보내기 전 SDK 단에서 미리 파라미터 유효성 검사\r\n if (!params.message && !params.messageId) {\r\n throw new Error('[CimeClient.ChatAPI] registerNotice requires either \"message\" or \"messageId\".');\r\n }\r\n\r\n await this.httpClient.post('/open/v1/chats/notice', params);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeDataList, CimeCategory, CimeSearchCategoriesParams } from '../types';\r\n\r\n/**\r\n * 카테고리(Category) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class CategoriesAPI {\r\n constructor(private readonly httpClient: AxiosInstance) {}\r\n\r\n /**\r\n * 라이브 설정 등에 사용할 카테고리를 키워드로 검색합니다.\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param params - 검색 키워드 및 페이지 크기 파라미터\r\n * @returns 검색된 카테고리 목록\r\n */\r\n public async searchCategories(params?: CimeSearchCategoriesParams): Promise<CimeDataList<CimeCategory>> {\r\n return this.httpClient.get<any, CimeDataList<CimeCategory>>('/open/v1/categories/search', {\r\n params,\r\n });\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeCursorList,\r\n CimeRestrictUserParams,\r\n CimeGetRestrictedUsersParams,\r\n CimeRestrictedUser,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 사용자 차단 및 추방(Restrict) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class RestrictAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 특정 사용자를 추방합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:USER_BLOCK`\r\n * @param params - 추방할 대상 채널 ID\r\n */\r\n public async restrictUser(params: CimeRestrictUserParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"WRITE:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.post('/open/v1/restrict-channels', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 추방된 사용자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:USER_BLOCK`\r\n * @param params - 커서 기반 페이징 파라미터 (size, next)\r\n * @returns 추방된 사용자 목록\r\n */\r\n public async getRestrictedUsers(\r\n params?: CimeGetRestrictedUsersParams\r\n ): Promise<CimeCursorList<CimeRestrictedUser>> {\r\n if (!this.options.scopes?.includes('READ:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"READ:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeCursorList<CimeRestrictedUser>>('/open/v1/restrict-channels', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 특정 사용자의 추방을 해제합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:USER_BLOCK`\r\n * @param params - 추방 해제할 대상 채널 ID\r\n */\r\n public async unrestrictUser(params: CimeRestrictUserParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"WRITE:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // Axios에서 DELETE 요청에 Request Body를 담으려면 두 번째 인자인 config의 data 필드에 넣어야 합니다.\r\n await this.httpClient.delete('/open/v1/restrict-channels', {\r\n data: params,\r\n });\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeSessionResponse, CimeSessionType, CimeEventName } from '../types';\r\n\r\n/**\r\n * 세션(Session) 및 이벤트 구독 제어를 담당하는 클래스입니다.\r\n */\r\nexport class SessionsAPI {\r\n constructor(private readonly httpClient: AxiosInstance) {}\r\n\r\n /**\r\n * WebSocket 연결을 위한 새로운 세션을 생성합니다.\r\n *\r\n * @param type - 세션 유형 ('USER' 또는 'CLIENT')\r\n * @returns WebSocket URL을 포함한 세션 정보\r\n */\r\n public async createSession(type: CimeSessionType): Promise<CimeSessionResponse> {\r\n const endpoint = type === 'USER' ? '/open/v1/sessions/auth' : '/open/v1/sessions/auth/client';\r\n return this.httpClient.get<any, CimeSessionResponse>(endpoint);\r\n }\r\n\r\n /**\r\n * 특정 세션에 이벤트를 구독합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @param event - 구독할 이벤트 이름 (chat, donation, subscription)\r\n * @param sessionKey - 세션 키\r\n */\r\n public async subscribeEvent(event: CimeEventName, sessionKey: string): Promise<void> {\r\n await this.httpClient.post(`/open/v1/sessions/events/subscribe/${event}`, null, {\r\n params: { sessionKey },\r\n });\r\n }\r\n\r\n /**\r\n * 특정 세션에서 이벤트 구독을 해제합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @param event - 구독 해제할 이벤트 이름\r\n * @param sessionKey - 세션 키\r\n */\r\n public async unsubscribeEvent(event: CimeEventName, sessionKey: string): Promise<void> {\r\n await this.httpClient.post(`/open/v1/sessions/events/unsubscribe/${event}`, null, {\r\n params: { sessionKey },\r\n });\r\n }\r\n}","import WebSocket from 'ws';\r\nimport { EventEmitter } from 'events';\r\nimport { SessionsAPI } from '../api/sessions';\r\nimport { CimeEventClientOptions, CimeEventPayload } from '../types';\r\nimport { CimeChatEventData } from '../types/chat';\r\nimport { CimeDonationEventData } from '../types/donation';\r\nimport { CimeSubscriptionEventData } from '../types/subscription';\r\n\r\nexport type CimeLiveEventName = 'CHAT' | 'DONATION' | 'SUBSCRIPTION';\r\n\r\nexport declare interface CimeEventClient {\r\n on(event: 'CHAT', listener: (data: CimeChatEventData) => void): this;\r\n on(event: 'DONATION', listener: (data: CimeDonationEventData) => void): this;\r\n on(event: 'SUBSCRIPTION', listener: (data: CimeSubscriptionEventData) => void): this;\r\n \r\n on(event: 'connected', listener: () => void): this;\r\n on(event: 'disconnected', listener: () => void): this;\r\n on(event: 'error', listener: (error: Error) => void): this;\r\n on(event: 'reconnecting', listener: () => void): this;\r\n on(event: string | symbol, listener: (...args: any[]) => void): this;\r\n\r\n emit(event: 'CHAT', data: CimeChatEventData): boolean;\r\n emit(event: 'DONATION', data: CimeDonationEventData): boolean;\r\n emit(event: 'SUBSCRIPTION', data: CimeSubscriptionEventData): boolean;\r\n \r\n emit(event: 'connected'): boolean;\r\n emit(event: 'disconnected'): boolean;\r\n emit(event: 'error', error: Error): boolean;\r\n emit(event: 'reconnecting'): boolean;\r\n emit(event: string | symbol, ...args: any[]): boolean;\r\n}\r\n\r\n/**\r\n * ci.me API의 실시간 이벤트를 수신하기 위한 WebSocket 클라이언트입니다.\r\n */\r\nexport class CimeEventClient extends EventEmitter {\r\n private ws: WebSocket | null = null;\r\n private sessionKey: string | null = null;\r\n private pingTimer: NodeJS.Timeout | null = null;\r\n private reconnectTimer: NodeJS.Timeout | null = null;\r\n \r\n private isConnecting = false;\r\n private isIntentionalClose = false;\r\n \r\n private readonly activeSubscriptions = new Set<CimeLiveEventName>();\r\n\r\n constructor(\r\n private readonly sessionsApi: SessionsAPI,\r\n private readonly options: CimeEventClientOptions\r\n ) {\r\n super();\r\n }\r\n\r\n public async connect(): Promise<void> {\r\n if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) return;\r\n this.isConnecting = true;\r\n this.isIntentionalClose = false;\r\n\r\n try {\r\n const { url } = await this.sessionsApi.createSession(this.options.type);\r\n \r\n const parsedUrl = new URL(url);\r\n this.sessionKey = parsedUrl.searchParams.get('sessionKey');\r\n \r\n if (!this.sessionKey) {\r\n throw new Error('[CimeEventClient] Failed to extract sessionKey from URL.');\r\n }\r\n\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.on('open', async () => {\r\n this.isConnecting = false;\r\n this.startPing();\r\n this.emit('connected');\r\n\r\n for (const event of this.activeSubscriptions) {\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n await this.sessionsApi.subscribeEvent(apiEventName, this.sessionKey!).catch(err => {\r\n this.emit('error', new Error(`Failed to resubscribe ${event}: ${err.message}`));\r\n });\r\n }\r\n });\r\n\r\n this.ws.on('message', (data: WebSocket.RawData) => {\r\n this.handleMessage(data.toString());\r\n });\r\n\r\n this.ws.on('close', () => {\r\n this.cleanup();\r\n this.emit('disconnected');\r\n this.handleReconnect();\r\n });\r\n\r\n this.ws.on('error', (error) => {\r\n this.emit('error', error);\r\n });\r\n\r\n } catch (error) {\r\n this.isConnecting = false;\r\n this.emit('error', error as Error);\r\n this.handleReconnect(); \r\n }\r\n }\r\n\r\n /**\r\n * 실시간 이벤트를 구독합니다.\r\n * @param event - 'CHAT' | 'DONATION' | 'SUBSCRIPTION'\r\n */\r\n public async subscribe(event: CimeLiveEventName): Promise<void> {\r\n if (this.activeSubscriptions.size >= 30) {\r\n throw new Error('[CimeEventClient] Exceeded maximum 30 subscriptions per session.');\r\n }\r\n\r\n this.activeSubscriptions.add(event);\r\n \r\n // API 통신 시에는 소문자로 변환하여 전송합니다.\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n\r\n if (this.sessionKey && this.ws?.readyState === WebSocket.OPEN) {\r\n await this.sessionsApi.subscribeEvent(apiEventName, this.sessionKey);\r\n }\r\n }\r\n\r\n /**\r\n * 실시간 이벤트 구독을 해제합니다.\r\n * @param event - 'CHAT' | 'DONATION' | 'SUBSCRIPTION'\r\n */\r\n public async unsubscribe(event: CimeLiveEventName): Promise<void> {\r\n this.activeSubscriptions.delete(event);\r\n\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n\r\n if (this.sessionKey && this.ws?.readyState === WebSocket.OPEN) {\r\n await this.sessionsApi.unsubscribeEvent(apiEventName, this.sessionKey);\r\n }\r\n }\r\n\r\n public disconnect(): void {\r\n this.isIntentionalClose = true;\r\n this.activeSubscriptions.clear();\r\n this.cleanup();\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n }\r\n\r\n private handleMessage(message: string): void {\r\n try {\r\n const payload = JSON.parse(message);\r\n \r\n if (payload.action === 'PONG') return;\r\n\r\n if (payload.event && payload.data) {\r\n const typedPayload = payload as CimeEventPayload;\r\n this.emit(typedPayload.event as any, typedPayload.data);\r\n }\r\n } catch (error) {\r\n this.emit('error', new Error(`[CimeEventClient] Failed to parse message: ${message}`));\r\n }\r\n }\r\n\r\n private startPing(): void {\r\n const interval = this.options.pingInterval || 60000;\r\n this.pingTimer = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify({ type: 'PING' }));\r\n }\r\n }, interval);\r\n }\r\n\r\n private cleanup(): void {\r\n if (this.pingTimer) {\r\n clearInterval(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n this.isConnecting = false;\r\n }\r\n\r\n private async handleReconnect(): Promise<void> {\r\n if (this.isIntentionalClose) return;\r\n\r\n if (this.options.onTokenRefresh) {\r\n try {\r\n await this.options.onTokenRefresh();\r\n } catch (err) {\r\n this.emit('error', new Error('[CimeEventClient] Token refresh failed during reconnect.'));\r\n }\r\n }\r\n\r\n this.reconnectTimer = setTimeout(() => {\r\n this.emit('reconnecting');\r\n this.connect();\r\n }, 5000);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeClientOptions, CimeTokenResponse, CimeEventClientOptions } from './types';\r\nimport { createHttpClient } from './utils/httpClient';\r\nimport { AuthAPI } from './api/auth';\r\nimport { UsersAPI } from './api/users';\r\nimport { ChannelsAPI } from './api/channels';\r\nimport { LiveAPI } from './api/live';\r\nimport { ChatAPI } from './api/chat';\r\nimport { CategoriesAPI } from './api/categories';\r\nimport { RestrictAPI } from './api/restrict';\r\nimport { SessionsAPI } from './api/sessions';\r\nimport { CimeEventClient } from './ws/CimeEventClient';\r\n\r\n/**\r\n * ci.me API를 사용하기 위한 메인 클라이언트 클래스입니다.\r\n */\r\nexport class CimeClient {\r\n private readonly httpClient: AxiosInstance;\r\n private options: CimeClientOptions;\r\n\r\n public readonly auth: AuthAPI;\r\n public readonly users: UsersAPI;\r\n public readonly channels: ChannelsAPI;\r\n public readonly live: LiveAPI;\r\n public readonly chat: ChatAPI;\r\n public readonly categories: CategoriesAPI;\r\n public readonly restrict: RestrictAPI;\r\n public readonly sessions: SessionsAPI;\r\n\r\n constructor(options: CimeClientOptions) {\r\n // [버그 수정됨] accessToken이 없고, (clientId 또는 clientSecret이 없을 때) 에러를 발생시킵니다.\r\n if (!options.accessToken && (!options.clientId || !options.clientSecret)) {\r\n throw new Error('[CimeClient] Authentication credentials (accessToken OR clientId/Secret) are required.');\r\n }\r\n\r\n this.options = { ...options };\r\n this.httpClient = createHttpClient(this.options);\r\n\r\n this.auth = new AuthAPI(this.httpClient, { clientId: this.options.clientId, clientSecret: this.options.clientSecret });\r\n this.users = new UsersAPI(this.httpClient, this.options);\r\n this.channels = new ChannelsAPI(this.httpClient, this.options);\r\n this.live = new LiveAPI(this.httpClient, this.options);\r\n this.chat = new ChatAPI(this.httpClient, this.options);\r\n this.categories = new CategoriesAPI(this.httpClient);\r\n this.restrict = new RestrictAPI(this.httpClient, this.options);\r\n this.sessions = new SessionsAPI(this.httpClient);\r\n }\r\n\r\n public setAccessToken(token: string): void {\r\n this.options.accessToken = token;\r\n // httpClient 내부의 options 참조는 객체 참조이므로 속성만 바꿔주면 다음 요청부터 자동으로 반영됩니다.\r\n }\r\n\r\n /**\r\n * 실시간 이벤트를 수신하기 위한 WebSocket 클라이언트를 생성합니다.\r\n */\r\n public createEventClient(options: CimeEventClientOptions): CimeEventClient {\r\n if (options.refreshToken && !options.onTokenRefresh) {\r\n options.onTokenRefresh = async () => {\r\n try {\r\n const tokenInfo = await this.auth.refresh(options.refreshToken!);\r\n this.setAccessToken(tokenInfo.accessToken);\r\n options.refreshToken = tokenInfo.refreshToken;\r\n } catch (error) {\r\n throw new Error('자동 토큰 갱신에 실패했습니다.');\r\n }\r\n };\r\n }\r\n return new CimeEventClient(this.sessions, options);\r\n }\r\n\r\n /** * OAuth 인증 플로우를 통해 Access Token을 발급받고 클라이언트에 설정합니다.\r\n * @param code Redirect URI로 전달받은 인가 코드\r\n * @throws 인증 정보(clientId/Secret)가 없으면 에러를 반환합니다.\r\n */\r\n public async authorize(code: string): Promise<CimeTokenResponse> {\r\n if (!this.options.clientId || !this.options.clientSecret) {\r\n throw new Error('[CimeClient] OAuth authentication requires clientId and clientSecret to be set in options.');\r\n }\r\n\r\n const tokenResponse = await this.auth.get(code);\r\n this.setAccessToken(tokenResponse.accessToken);\r\n return tokenResponse;\r\n }\r\n}","import { CimeChatEventData } from '../types/chat';\r\n\r\n/**\r\n * 채팅 메시지 내의 이모티콘 토큰을 <img> 태그로 변환합니다.\r\n * 따로 UI를 만드실 계획이 아니시라면, 별 쓸모는 없습니다.\r\n * @param data 채팅 이벤트 데이터 (content, emojis)\r\n * @param className <img> 태그에 부여할 CSS 클래스명 (기본값: 'cime-emoji')\r\n * @returns 변환된 HTML 문자열\r\n */\r\nexport function renderChatEmojisToHTML(\r\n data: Pick<CimeChatEventData, 'content' | 'emojis'>,\r\n className: string = 'cime-emoji'\r\n): string {\r\n if (!data.emojis || Object.keys(data.emojis).length === 0) {\r\n return data.content;\r\n }\r\n\r\n let htmlMessage = data.content;\r\n\r\n for (const [token, imageUrl] of Object.entries(data.emojis)) {\r\n // 1. 토큰 내의 정규식 특수문자 안전하게 이스케이프 처리\r\n const escapedToken = token.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n const regex = new RegExp(escapedToken, 'g');\r\n\r\n // 2. replace의 두 번째 인자로 문자열 대신 '콜백 함수'를 사용하여\r\n // '$$' 기호가 단일 '$'로 치환되는 JavaScript 고유의 버그를 방지합니다.\r\n htmlMessage = htmlMessage.replace(regex, () => {\r\n return `<img src=\"${imageUrl}\" alt=\"${token}\" class=\"${className}\" />`;\r\n });\r\n }\r\n\r\n return htmlMessage;\r\n}","import { checkVersion } from './utils/version';\r\ncheckVersion();\r\n\r\nexport { CimeClient } from './client';\r\n\r\nexport { CimeAPIError } from './errors/CimeAPIError';\r\n\r\nexport { CimeEventClient, CimeLiveEventName } from './ws/CimeEventClient';\r\n\r\nexport * from './types';\r\n\r\nexport * from './utils/chatUtils';\r\nexport { getVersion } from './utils/version';"]}
1
+ {"version":3,"sources":["../package.json","../src/utils/version.ts","../src/errors/CimeAPIError.ts","../src/utils/httpClient.ts","../src/api/auth.ts","../src/api/users.ts","../src/api/channels.ts","../src/api/live.ts","../src/api/chat.ts","../src/api/categories.ts","../src/api/restrict.ts","../src/api/sessions.ts","../src/ws/CimeEventClient.ts","../src/client.ts","../src/utils/chatUtils.ts","../src/index.ts"],"names":["axios","axiosRetry","EventEmitter","WebSocket"],"mappings":";;;;;;;;;;;;;;;;AAAA,IAAA,eAAA,GAAA;AAAA,EACE,IAAA,EAAQ,UAAA;AAAA,EACR,OAAA,EAAW,OAAA;AAAA,EACX,WAAA,EAAe,+DAAA;AAAA,EACf,IAAA,EAAQ,eAAA;AAAA,EACR,MAAA,EAAU,gBAAA;AAAA,EACV,KAAA,EAAS,iBAAA;AAAA,EACT,KAAA,EAAS;AAAA,IACP;AAAA,GACF;AAAA,EACA,OAAA,EAAW;AAAA,IACT,GAAA,EAAK;AAAA,MACH,OAAA,EAAW,iBAAA;AAAA,MACX,MAAA,EAAU,kBAAA;AAAA,MACV,KAAA,EAAS;AAAA;AACX,GACF;AAAA,EACA,OAAA,EAAW;AAAA,IACT,KAAA,EAAS,MAAA;AAAA,IACT,GAAA,EAAO,cAAA;AAAA,IACP,IAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAa;AAAA,GACf;AAAA,EACA,QAAA,EAAY;AAAA,IACV,MAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,MAAA,EAAU,YAAA;AAAA,EACV,OAAA,EAAW,KAAA;AAAA,EACX,UAAA,EAAc;AAAA,IACZ,IAAA,EAAQ,KAAA;AAAA,IACR,GAAA,EAAO;AAAA,GACT;AAAA,EACA,IAAA,EAAQ,UAAA;AAAA,EACR,YAAA,EAAgB;AAAA,IACd,KAAA,EAAS,SAAA;AAAA,IACT,aAAA,EAAe,QAAA;AAAA,IACf,EAAA,EAAM;AAAA,GACR;AAAA,EACA,eAAA,EAAmB;AAAA,IACjB,aAAA,EAAe,SAAA;AAAA,IACf,WAAA,EAAa,SAAA;AAAA,IACb,IAAA,EAAQ,QAAA;AAAA,IACR,UAAA,EAAc,QAAA;AAAA,IACd,MAAA,EAAU;AAAA;AAEd,CAAA;;;ACzCO,SAAS,UAAA,GAAqB;AACnC,EAAA,OAAO,eAAA,CAAI,OAAA;AACb;AAMA,eAAsB,YAAA,GAA8B;AAChD,EAAA,IAAI;AACA,IAAA,MAAM,eAAe,eAAA,CAAI,OAAA;AACzB,IAAA,MAAM,cAAc,eAAA,CAAI,IAAA;AAExB,IAAA,MAAM,EAAE,MAAM,MAAA,EAAO,GAAI,MAAMA,sBAAA,CAAM,GAAA,CAAI,CAAA,2BAAA,EAA8B,WAAW,CAAA,OAAA,CAAA,EAAW;AAAA,MACzF,OAAA,EAAS;AAAA,KACZ,CAAA;AAED,IAAA,IAAI,WAAW,GAAA,IAAO,CAAC,IAAA,IAAQ,CAAC,KAAK,OAAA,EAAS;AAC1C,MAAA;AAAA,IACJ;AAEA,IAAA,MAAM,gBAAgB,IAAA,CAAK,OAAA;AAE3B,IAAA,IAAI,cAAA,CAAe,YAAA,EAAc,aAAa,CAAA,EAAG;AAC7C,MAAA,OAAA,CAAQ,GAAA,CAAI;AAAA,sDAAA,CAA0D,CAAA;AACtE,MAAA,OAAA,CAAQ,IAAI,CAAA,0FAAA,CAA8B,CAAA;AAC1C,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,2BAAA,EAAU,YAAY,CAAA,+BAAA,EAAc,aAAa,CAAA,CAAE,CAAA;AAC/D,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,oBAAA,EAAuB,WAAW,CAAA,CAAA,EAAI,aAAa,CAAA,CAAE,CAAA;AACjE,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA;AAAA,CAA0D,CAAA;AAAA,IAC1E;AAAA,EACJ,SAAS,KAAA,EAAO;AACZ,IAAA;AAAA,EACJ;AACJ;AAMA,SAAS,cAAA,CAAe,OAAe,MAAA,EAAyB;AAC5D,EAAA,MAAM,SAAS,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA,CAAE,IAAI,MAAM,CAAA;AAC1C,EAAA,MAAM,SAAS,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,CAAE,IAAI,MAAM,CAAA;AAE3C,EAAA,MAAM,YAAY,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,MAAA,EAAQ,OAAO,MAAM,CAAA;AAEvD,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,EAAW,CAAA,EAAA,EAAK;AAChC,IAAA,MAAM,CAAA,GAAI,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA;AACvB,IAAA,MAAM,CAAA,GAAI,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA;AAEvB,IAAA,IAAI,CAAA,GAAI,GAAG,OAAO,IAAA;AAClB,IAAA,IAAI,CAAA,GAAI,GAAG,OAAO,KAAA;AAAA,EACtB;AAEA,EAAA,OAAO,KAAA;AACX;;;ACtDO,IAAM,YAAA,GAAN,MAAM,aAAA,SAAqB,KAAA,CAAM;AAAA,EACpB,UAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,YAAY,aAAA,EAAkC;AAC1C,IAAA,KAAA,CAAM,cAAc,OAAO,CAAA;AAC3B,IAAA,IAAA,CAAK,IAAA,GAAO,cAAA;AACZ,IAAA,IAAA,CAAK,aAAa,aAAA,CAAc,UAAA;AAGhC,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,aAAA,CAAa,SAAS,CAAA;AAAA,EACtD;AACJ;;;ACXO,SAAS,iBAAiB,OAAA,EAA2C;AACxE,EAAA,MAAM,MAAA,GAASA,uBAAM,MAAA,CAAO;AAAA,IACxB,OAAA,EAAS,2BAAA;AAAA,IACT,OAAA,EAAS,QAAQ,OAAA,IAAW,GAAA;AAAA,IAC5B,OAAA,EAAS;AAAA,MACL,cAAA,EAAgB,kBAAA;AAAA,MAChB,YAAA,EAAc,CAAA,QAAA,EAAW,UAAA,EAAY,CAAA,OAAA;AAAA;AACzC,GACH,CAAA;AAED,EAAA,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAuC;AACpE,IAAA,IAAI,QAAQ,WAAA,EAAa;AACrB,MAAA,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,QAAQ,WAAW,CAAA,CAAA;AAAA,IACnE;AACA,IAAA,IAAI,OAAA,CAAQ,QAAA,IAAY,OAAA,CAAQ,YAAA,EAAc;AAC1C,MAAA,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,GAAI,OAAA,CAAQ,QAAA;AACtC,MAAA,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA,GAAI,OAAA,CAAQ,YAAA;AAAA,IAC9C;AACA,IAAA,OAAO,MAAA;AAAA,EACX,CAAC,CAAA;AAED,EAAAC,2BAAA,CAAW,MAAA,EAAQ;AAAA,IACf,OAAA,EAAS,QAAQ,OAAA,IAAW,CAAA;AAAA,IAC5B,YAAYA,2BAAA,CAAW,gBAAA;AAAA,IACvB,cAAA,EAAgB,CAAC,KAAA,KAAsB;AACvC,MAAA,OAAOA,4BAAW,iCAAA,CAAkC,KAAK,CAAA,IAAK,KAAA,CAAM,UAAU,MAAA,KAAW,GAAA;AAAA,IACzF;AAAA,GACH,CAAA;AAED,EAAA,MAAA,CAAO,aAAa,QAAA,CAAS,GAAA;AAAA,IACzB,CAAC,QAAA,KAAgD;AACjD,MAAA,OAAO,SAAS,IAAA,CAAK,OAAA;AAAA,IACrB,CAAA;AAAA,IACA,CAAC,KAAA,KAAyC;AAC1C,MAAA,IAAI,KAAA,CAAM,QAAA,IAAY,KAAA,CAAM,QAAA,CAAS,IAAA,EAAM;AACvC,QAAA,MAAM,IAAI,YAAA,CAAa,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AAAA,MAC9C;AACA,MAAA,MAAM,KAAA;AAAA,IACN;AAAA,GACJ;AAEA,EAAA,OAAO,MAAA;AACX;;;AChDO,IAAM,UAAN,MAAc;AAAA,EACjB,WAAA,CACqB,MACA,MAAA,EACnB;AAFmB,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAClB;AAAA,EAFkB,IAAA;AAAA,EACA,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrB,MAAa,IAAI,IAAA,EAA0C;AACvD,IAAA,IAAA,CAAK,mBAAA,EAAoB;AAEzB,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,IAAA,CAAK,KAAwB,gBAAA,EAAkB;AAAA,MACvE,SAAA,EAAW,oBAAA;AAAA,MACX,QAAA,EAAU,KAAK,MAAA,CAAO,QAAA;AAAA,MACtB,YAAA,EAAc,KAAK,MAAA,CAAO,YAAA;AAAA,MAC1B;AAAA,KACH,CAAA;AAED,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,QAAQ,YAAA,EAAkD;AACnE,IAAA,IAAA,CAAK,mBAAA,EAAoB;AAEzB,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,IAAA,CAAK,KAAwB,gBAAA,EAAkB;AAAA,MACvE,SAAA,EAAW,eAAA;AAAA,MACX,QAAA,EAAU,KAAK,MAAA,CAAO,QAAA;AAAA,MACtB,YAAA,EAAc,KAAK,MAAA,CAAO,YAAA;AAAA,MAC1B;AAAA,KACH,CAAA;AAED,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAA,GAA4B;AAChC,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,YAAY,CAAC,IAAA,CAAK,OAAO,YAAA,EAAc;AACpD,MAAA,MAAM,IAAI,KAAA;AAAA,QACN;AAAA,OACJ;AAAA,IACJ;AAAA,EACJ;AACJ,CAAA;;;AC/CO,IAAM,WAAN,MAAe;AAAA,EAClB,WAAA,CAA6B,YAA4C,OAAA,EAA4B;AAAxE,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAA4C,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAA6B;AAAA,EAAzE,UAAA;AAAA,EAA4C,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAczE,MAAa,GAAA,GAAyB;AAClC,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,WAAW,CAAA,EAAG;AAC7C,MAAA,MAAM,IAAI,MAAM,kLAA+D,CAAA;AAAA,IACnF;AAEA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAmB,mBAAmB,CAAA;AAAA,EACjE;AACJ,CAAA;;;ACZO,IAAM,cAAN,MAAkB;AAAA,EACrB,WAAA,CAA6B,YAA4C,OAAA,EAA4B;AAAxE,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAA4C,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAA6B;AAAA,EAAzE,UAAA;AAAA,EAA4C,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAazE,MAAa,YAAY,UAAA,EAAuE;AAE5F,IAAA,MAAM,SAAA,GAAY,MAAM,OAAA,CAAQ,UAAU,IAAI,UAAA,CAAW,IAAA,CAAK,GAAG,CAAA,GAAI,UAAA;AAErE,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAwC,mBAAA,EAAqB;AAAA,MACpF,MAAA,EAAQ,EAAE,UAAA,EAAY,SAAA;AAAU,KAC/B,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,aAAa,MAAA,EAA0E;AAChG,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,cAAc,CAAA,EAAG;AAChD,MAAA,MAAM,IAAI,MAAM,wLAAqE,CAAA;AAAA,IACzF;AACA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAqC,6BAAA,EAA+B;AAAA,MAC3F;AAAA,KACC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,eAAe,MAAA,EAA8E;AACtG,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,mBAAmB,CAAA,EAAG;AACrD,MAAA,MAAM,IAAI,MAAM,6LAA0E,CAAA;AAAA,IAC9F;AACA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAuC,+BAAA,EAAiC;AAAA,MAC/F;AAAA,KACC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,WAAA,GAAkD;AAC3D,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,cAAc,CAAA,EAAG;AAChD,MAAA,MAAM,IAAI,MAAM,wLAAqE,CAAA;AAAA,IACzF;AACA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAoC,mCAAmC,CAAA;AAAA,EAClG;AACJ,CAAA;;;ACvEO,IAAM,UAAN,MAAc;AAAA,EACjB,WAAA,CAA6B,YAA4C,OAAA,EAA4B;AAAxE,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAA4C,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAA6B;AAAA,EAAzE,UAAA;AAAA,EAA4C,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASzE,MAAa,SAAS,MAAA,EAA6D;AAC/E,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAmC,gBAAA,EAAkB;AAAA,MAC5E;AAAA,KACC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,WAAA,GAAwC;AACjD,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,2BAA2B,CAAA,EAAG;AAC7D,MAAA,MAAM,IAAI,MAAM,iMAA8E,CAAA;AAAA,IAClG;AACA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAA0B,wBAAwB,CAAA;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,eAAe,MAAA,EAAoD;AAC5E,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,4BAA4B,CAAA,EAAG;AAC9D,MAAA,MAAM,IAAI,MAAM,kMAA+E,CAAA;AAAA,IACnG;AACA,IAAA,MAAM,IAAA,CAAK,UAAA,CAAW,KAAA,CAAM,wBAAA,EAA0B,MAAM,CAAA;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,YAAA,GAAuC;AAChD,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,sBAAsB,CAAA,EAAG;AACxD,MAAA,MAAM,IAAI,MAAM,4LAAyE,CAAA;AAAA,IAC7F;AACA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAwB,sBAAsB,CAAA;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,cAAc,SAAA,EAA4C;AAEnE,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAyB,CAAA,IAAA,EAAO,SAAS,CAAA,YAAA,CAAc,CAAA;AAAA,EAClF;AACJ,CAAA;;;ACzEO,IAAM,UAAN,MAAc;AAAA,EACjB,WAAA,CAA6B,YAA4C,OAAA,EAA4B;AAAxE,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAA4C,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAA6B;AAAA,EAAzE,UAAA;AAAA,EAA4C,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASzE,MAAa,WAAA,GAAyC;AAClD,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,yBAAyB,CAAA,EAAG;AAC3D,MAAA,MAAM,IAAI,MAAM,+LAA4E,CAAA;AAAA,IAChG;AACA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAA2B,yBAAyB,CAAA;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,eAAe,MAAA,EAAqD;AAC7E,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,0BAA0B,CAAA,EAAG;AAC5D,MAAA,MAAM,IAAI,MAAM,gMAA6E,CAAA;AAAA,IACjG;AACA,IAAA,MAAM,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,yBAAA,EAA2B,MAAM,CAAA;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,YAAY,MAAA,EAAyE;AAC9F,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,iBAAiB,CAAA,EAAG;AACnD,MAAA,MAAM,IAAI,MAAM,uLAAoE,CAAA;AAAA,IACxF;AACA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,IAAA,CAAuC,qBAAA,EAAuB,MAAM,CAAA;AAAA,EAC/F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,eAAe,MAAA,EAAqD;AAC7E,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,wBAAwB,CAAA,EAAG;AAC1D,MAAA,MAAM,IAAI,MAAM,8LAA2E,CAAA;AAAA,IAC/F;AAEA,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,IAAW,CAAC,OAAO,SAAA,EAAW;AAC1C,MAAA,MAAM,IAAI,MAAM,+EAA+E,CAAA;AAAA,IAC/F;AAEA,IAAA,MAAM,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,uBAAA,EAAyB,MAAM,CAAA;AAAA,EAC9D;AACJ,CAAA;;;ACxEO,IAAM,gBAAN,MAAoB;AAAA,EACvB,YAA6B,UAAA,EAA2B;AAA3B,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAAA,EAA4B;AAAA,EAA5B,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS7B,MAAa,iBAAiB,MAAA,EAA0E;AACpG,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAqC,4BAAA,EAA8B;AAAA,MAC1F;AAAA,KACC,CAAA;AAAA,EACL;AACJ,CAAA;;;ACTO,IAAM,cAAN,MAAkB;AAAA,EACrB,WAAA,CAA6B,YAA4C,OAAA,EAA4B;AAAxE,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAA4C,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAA6B;AAAA,EAAzE,UAAA;AAAA,EAA4C,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASzE,MAAa,aAAa,MAAA,EAA+C;AACrE,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,kBAAkB,CAAA,EAAG;AACpD,MAAA,MAAM,IAAI,MAAM,4LAAyE,CAAA;AAAA,IAC7F;AACA,IAAA,MAAM,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,4BAAA,EAA8B,MAAM,CAAA;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,mBACT,MAAA,EAC2C;AAC3C,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,iBAAiB,CAAA,EAAG;AACnD,MAAA,MAAM,IAAI,MAAM,2LAAwE,CAAA;AAAA,IAC5F;AACA,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAA6C,4BAAA,EAA8B;AAAA,MAClG;AAAA,KACC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,eAAe,MAAA,EAA+C;AACvE,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,QAAA,CAAS,kBAAkB,CAAA,EAAG;AACpD,MAAA,MAAM,IAAI,MAAM,4LAAyE,CAAA;AAAA,IAC7F;AAEA,IAAA,MAAM,IAAA,CAAK,UAAA,CAAW,MAAA,CAAO,4BAAA,EAA8B;AAAA,MAC3D,IAAA,EAAM;AAAA,KACL,CAAA;AAAA,EACL;AACJ,CAAA;;;AC1DO,IAAM,cAAN,MAAkB;AAAA,EACrB,YAA6B,UAAA,EAA2B;AAA3B,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAAA,EAA4B;AAAA,EAA5B,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ7B,MAAa,cAAc,IAAA,EAAqD;AAC5E,IAAA,MAAM,QAAA,GAAW,IAAA,KAAS,MAAA,GAAS,wBAAA,GAA2B,+BAAA;AAC9D,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAA8B,QAAQ,CAAA;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,cAAA,CAAe,KAAA,EAAsB,UAAA,EAAmC;AACjF,IAAA,MAAM,KAAK,UAAA,CAAW,IAAA,CAAK,CAAA,mCAAA,EAAsC,KAAK,IAAI,IAAA,EAAM;AAAA,MAChF,MAAA,EAAQ,EAAE,UAAA;AAAW,KACpB,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,gBAAA,CAAiB,KAAA,EAAsB,UAAA,EAAmC;AACnF,IAAA,MAAM,KAAK,UAAA,CAAW,IAAA,CAAK,CAAA,qCAAA,EAAwC,KAAK,IAAI,IAAA,EAAM;AAAA,MAClF,MAAA,EAAQ,EAAE,UAAA;AAAW,KACpB,CAAA;AAAA,EACL;AACJ,CAAA;ACVO,IAAM,eAAA,GAAN,cAA8BC,mBAAA,CAAa;AAAA,EAW9C,WAAA,CACqB,aACA,OAAA,EACnB;AACE,IAAA,KAAA,EAAM;AAHW,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAGrB;AAAA,EAJqB,WAAA;AAAA,EACA,OAAA;AAAA,EAZb,EAAA,GAAuB,IAAA;AAAA,EACvB,UAAA,GAA4B,IAAA;AAAA,EAC5B,SAAA,GAAmC,IAAA;AAAA,EACnC,cAAA,GAAwC,IAAA;AAAA,EAExC,YAAA,GAAe,KAAA;AAAA,EACf,kBAAA,GAAqB,KAAA;AAAA,EAEZ,mBAAA,uBAA0B,GAAA,EAAuB;AAAA,EASlE,MAAa,OAAA,GAAyB;AAClC,IAAA,IAAI,KAAK,YAAA,IAAgB,IAAA,CAAK,EAAA,EAAI,UAAA,KAAeC,2BAAU,IAAA,EAAM;AACjE,IAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,IAAA,IAAA,CAAK,kBAAA,GAAqB,KAAA;AAE1B,IAAA,IAAI;AACA,MAAA,MAAM,EAAE,KAAI,GAAI,MAAM,KAAK,WAAA,CAAY,aAAA,CAAc,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA;AAEtE,MAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,GAAG,CAAA;AAC7B,MAAA,IAAA,CAAK,UAAA,GAAa,SAAA,CAAU,YAAA,CAAa,GAAA,CAAI,YAAY,CAAA;AAEzD,MAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AAClB,QAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,MAC9E;AAEA,MAAA,IAAA,CAAK,EAAA,GAAK,IAAIA,0BAAA,CAAU,GAAG,CAAA;AAE3B,MAAA,IAAA,CAAK,EAAA,CAAG,EAAA,CAAG,MAAA,EAAQ,YAAY;AAC3B,QAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,QAAA,IAAA,CAAK,SAAA,EAAU;AACf,QAAA,IAAA,CAAK,KAAK,WAAW,CAAA;AAErB,QAAA,KAAA,MAAW,KAAA,IAAS,KAAK,mBAAA,EAAqB;AAC1C,UAAA,MAAM,YAAA,GAAe,MAAM,WAAA,EAAY;AACvC,UAAA,MAAM,IAAA,CAAK,YAAY,cAAA,CAAe,YAAA,EAAc,KAAK,UAAW,CAAA,CAAE,MAAM,CAAA,GAAA,KAAO;AAC/E,YAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,KAAK,CAAA,EAAA,EAAK,GAAA,CAAI,OAAO,CAAA,CAAE,CAAC,CAAA;AAAA,UAClF,CAAC,CAAA;AAAA,QACL;AAAA,MACJ,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,EAAA,CAAG,EAAA,CAAG,SAAA,EAAW,CAAC,IAAA,KAA4B;AAC/C,QAAA,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,QAAA,EAAU,CAAA;AAAA,MACtC,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,EAAA,CAAG,EAAA,CAAG,OAAA,EAAS,MAAM;AACtB,QAAA,IAAA,CAAK,OAAA,EAAQ;AACb,QAAA,IAAA,CAAK,KAAK,cAAc,CAAA;AACxB,QAAA,IAAA,CAAK,eAAA,EAAgB;AAAA,MACzB,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,EAAA,CAAG,EAAA,CAAG,OAAA,EAAS,CAAC,KAAA,KAAU;AAC3B,QAAA,IAAA,CAAK,IAAA,CAAK,SAAS,KAAK,CAAA;AAAA,MAC5B,CAAC,CAAA;AAAA,IAEL,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,MAAA,IAAA,CAAK,IAAA,CAAK,SAAS,KAAc,CAAA;AACjC,MAAA,IAAA,CAAK,eAAA,EAAgB;AAAA,IACzB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,UAAU,KAAA,EAAyC;AAC5D,IAAA,IAAI,IAAA,CAAK,mBAAA,CAAoB,IAAA,IAAQ,EAAA,EAAI;AACrC,MAAA,MAAM,IAAI,MAAM,kEAAkE,CAAA;AAAA,IACtF;AAEA,IAAA,IAAA,CAAK,mBAAA,CAAoB,IAAI,KAAK,CAAA;AAGlC,IAAA,MAAM,YAAA,GAAe,MAAM,WAAA,EAAY;AAEvC,IAAA,IAAI,KAAK,UAAA,IAAc,IAAA,CAAK,EAAA,EAAI,UAAA,KAAeA,2BAAU,IAAA,EAAM;AAC3D,MAAA,MAAM,IAAA,CAAK,WAAA,CAAY,cAAA,CAAe,YAAA,EAAc,KAAK,UAAU,CAAA;AAAA,IACvE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,YAAY,KAAA,EAAyC;AAC9D,IAAA,IAAA,CAAK,mBAAA,CAAoB,OAAO,KAAK,CAAA;AAErC,IAAA,MAAM,YAAA,GAAe,MAAM,WAAA,EAAY;AAEvC,IAAA,IAAI,KAAK,UAAA,IAAc,IAAA,CAAK,EAAA,EAAI,UAAA,KAAeA,2BAAU,IAAA,EAAM;AAC3D,MAAA,MAAM,IAAA,CAAK,WAAA,CAAY,gBAAA,CAAiB,YAAA,EAAc,KAAK,UAAU,CAAA;AAAA,IACzE;AAAA,EACJ;AAAA,EAEO,UAAA,GAAmB;AACtB,IAAA,IAAA,CAAK,kBAAA,GAAqB,IAAA;AAC1B,IAAA,IAAA,CAAK,oBAAoB,KAAA,EAAM;AAC/B,IAAA,IAAA,CAAK,OAAA,EAAQ;AACb,IAAA,IAAI,KAAK,EAAA,EAAI;AACT,MAAA,IAAA,CAAK,GAAG,KAAA,EAAM;AACd,MAAA,IAAA,CAAK,EAAA,GAAK,IAAA;AAAA,IACd;AAAA,EACJ;AAAA,EAEQ,cAAc,OAAA,EAAuB;AACzC,IAAA,IAAI;AACA,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AAElC,MAAA,IAAI,OAAA,CAAQ,WAAW,MAAA,EAAQ;AAE/B,MAAA,IAAI,OAAA,CAAQ,KAAA,IAAS,OAAA,CAAQ,IAAA,EAAM;AAC/B,QAAA,MAAM,YAAA,GAAe,OAAA;AACrB,QAAA,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,KAAA,EAAc,YAAA,CAAa,IAAI,CAAA;AAAA,MAC1D;AAAA,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,KAAK,OAAA,EAAS,IAAI,MAAM,CAAA,2CAAA,EAA8C,OAAO,EAAE,CAAC,CAAA;AAAA,IACzF;AAAA,EACJ;AAAA,EAEQ,SAAA,GAAkB;AACtB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,YAAA,IAAgB,GAAA;AAC9C,IAAA,IAAA,CAAK,SAAA,GAAY,YAAY,MAAM;AAC/B,MAAA,IAAI,IAAA,CAAK,EAAA,EAAI,UAAA,KAAeA,0BAAA,CAAU,IAAA,EAAM;AACxC,QAAA,IAAA,CAAK,EAAA,CAAG,KAAK,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAC,CAAA;AAAA,MACjD;AAAA,IACJ,GAAG,QAAQ,CAAA;AAAA,EACf;AAAA,EAEQ,OAAA,GAAgB;AACpB,IAAA,IAAI,KAAK,SAAA,EAAW;AAChB,MAAA,aAAA,CAAc,KAAK,SAAS,CAAA;AAC5B,MAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AAAA,IACrB;AACA,IAAA,IAAI,KAAK,cAAA,EAAgB;AACrB,MAAA,YAAA,CAAa,KAAK,cAAc,CAAA;AAChC,MAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AAAA,IAC1B;AACA,IAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AAAA,EACxB;AAAA,EAEA,MAAc,eAAA,GAAiC;AAC3C,IAAA,IAAI,KAAK,kBAAA,EAAoB;AAE7B,IAAA,IAAI,IAAA,CAAK,QAAQ,cAAA,EAAgB;AAC7B,MAAA,IAAI;AACA,QAAA,MAAM,IAAA,CAAK,QAAQ,cAAA,EAAe;AAAA,MACtC,SAAS,GAAA,EAAK;AACV,QAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,IAAI,KAAA,CAAM,0DAA0D,CAAC,CAAA;AAAA,MAC5F;AAAA,IACJ;AAEA,IAAA,IAAA,CAAK,cAAA,GAAiB,WAAW,MAAM;AACnC,MAAA,IAAA,CAAK,KAAK,cAAc,CAAA;AACxB,MAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,IACjB,GAAG,GAAI,CAAA;AAAA,EACX;AACJ;;;ACvLO,IAAM,aAAN,MAAiB;AAAA,EACH,UAAA;AAAA,EACT,OAAA;AAAA,EAEQ,IAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EAEhB,YAAY,OAAA,EAA4B;AAEpC,IAAA,IAAI,CAAC,QAAQ,WAAA,KAAgB,CAAC,QAAQ,QAAA,IAAY,CAAC,QAAQ,YAAA,CAAA,EAAe;AACtE,MAAA,MAAM,IAAI,MAAM,wFAAwF,CAAA;AAAA,IAC5G;AAEA,IAAA,IAAA,CAAK,OAAA,GAAU,EAAE,GAAG,OAAA,EAAQ;AAC5B,IAAA,IAAA,CAAK,UAAA,GAAa,gBAAA,CAAiB,IAAA,CAAK,OAAO,CAAA;AAE/C,IAAA,IAAA,CAAK,IAAA,GAAO,IAAI,OAAA,CAAQ,IAAA,CAAK,YAAY,EAAE,QAAA,EAAU,IAAA,CAAK,OAAA,CAAQ,QAAA,EAAU,YAAA,EAAc,IAAA,CAAK,OAAA,CAAQ,cAAc,CAAA;AACrH,IAAA,IAAA,CAAK,QAAQ,IAAI,QAAA,CAAS,IAAA,CAAK,UAAA,EAAY,KAAK,OAAO,CAAA;AACvD,IAAA,IAAA,CAAK,WAAW,IAAI,WAAA,CAAY,IAAA,CAAK,UAAA,EAAY,KAAK,OAAO,CAAA;AAC7D,IAAA,IAAA,CAAK,OAAO,IAAI,OAAA,CAAQ,IAAA,CAAK,UAAA,EAAY,KAAK,OAAO,CAAA;AACrD,IAAA,IAAA,CAAK,OAAO,IAAI,OAAA,CAAQ,IAAA,CAAK,UAAA,EAAY,KAAK,OAAO,CAAA;AACrD,IAAA,IAAA,CAAK,UAAA,GAAa,IAAI,aAAA,CAAc,IAAA,CAAK,UAAU,CAAA;AACnD,IAAA,IAAA,CAAK,WAAW,IAAI,WAAA,CAAY,IAAA,CAAK,UAAA,EAAY,KAAK,OAAO,CAAA;AAC7D,IAAA,IAAA,CAAK,QAAA,GAAW,IAAI,WAAA,CAAY,IAAA,CAAK,UAAU,CAAA;AAAA,EACnD;AAAA,EAEO,eAAe,KAAA,EAAqB;AACvC,IAAA,IAAA,CAAK,QAAQ,WAAA,GAAc,KAAA;AAAA,EAE/B;AAAA;AAAA;AAAA;AAAA,EAKO,kBAAkB,OAAA,EAAkD;AACvE,IAAA,IAAI,OAAA,CAAQ,YAAA,IAAgB,CAAC,OAAA,CAAQ,cAAA,EAAgB;AACjD,MAAA,OAAA,CAAQ,iBAAiB,YAAY;AACjC,QAAA,IAAI;AACA,UAAA,MAAM,YAAY,MAAM,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,QAAQ,YAAa,CAAA;AAC/D,UAAA,IAAA,CAAK,cAAA,CAAe,UAAU,WAAW,CAAA;AACzC,UAAA,OAAA,CAAQ,eAAe,SAAA,CAAU,YAAA;AAAA,QACrC,SAAS,KAAA,EAAO;AACZ,UAAA,MAAM,IAAI,MAAM,oFAAmB,CAAA;AAAA,QACvC;AAAA,MACJ,CAAA;AAAA,IACJ;AACA,IAAA,OAAO,IAAI,eAAA,CAAgB,IAAA,CAAK,QAAA,EAAU,OAAO,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,UAAU,IAAA,EAA0C;AAC7D,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,YAAY,CAAC,IAAA,CAAK,QAAQ,YAAA,EAAc;AACtD,MAAA,MAAM,IAAI,MAAM,4FAA4F,CAAA;AAAA,IAChH;AAEA,IAAA,MAAM,aAAA,GAAgB,MAAM,IAAA,CAAK,IAAA,CAAK,IAAI,IAAI,CAAA;AAC9C,IAAA,IAAA,CAAK,cAAA,CAAe,cAAc,WAAW,CAAA;AAC7C,IAAA,OAAO,aAAA;AAAA,EACX;AACJ;;;AC3EO,SAAS,sBAAA,CACZ,IAAA,EACA,SAAA,GAAoB,YAAA,EACd;AACN,EAAA,IAAI,CAAC,KAAK,MAAA,IAAU,MAAA,CAAO,KAAK,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG;AACvD,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EAChB;AAEA,EAAA,IAAI,cAAc,IAAA,CAAK,OAAA;AAEvB,EAAA,KAAA,MAAW,CAAC,OAAO,QAAQ,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,EAAG;AAEzD,IAAA,MAAM,YAAA,GAAe,KAAA,CAAM,OAAA,CAAQ,qBAAA,EAAuB,MAAM,CAAA;AAChE,IAAA,MAAM,KAAA,GAAQ,IAAI,MAAA,CAAO,YAAA,EAAc,GAAG,CAAA;AAI1C,IAAA,WAAA,GAAc,WAAA,CAAY,OAAA,CAAQ,KAAA,EAAO,MAAM;AAC3C,MAAA,OAAO,CAAA,UAAA,EAAa,QAAQ,CAAA,OAAA,EAAU,KAAK,YAAY,SAAS,CAAA,IAAA,CAAA;AAAA,IACpE,CAAC,CAAA;AAAA,EACL;AAEA,EAAA,OAAO,WAAA;AACX;;;AC/BA,YAAA,EAAa","file":"index.js","sourcesContent":["{\n \"name\": \"cime-sdk\",\n \"version\": \"1.0.2\",\n \"description\": \"A structural and object-oriented TypeScript SDK for ci.me API\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\"\n ],\n \"exports\": {\n \".\": {\n \"require\": \"./dist/index.js\",\n \"import\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.ts\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"keywords\": [\n \"cime\",\n \"sdk\",\n \"typescript\"\n ],\n \"author\": \"whitespaca\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/whitespaca/cime-sdk\"\n },\n \"type\": \"commonjs\",\n \"dependencies\": {\n \"axios\": \"^1.15.0\",\n \"axios-retry\": \"^4.5.0\",\n \"ws\": \"^8.20.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.6.0\",\n \"@types/ws\": \"^8.18.1\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.2\",\n \"vitest\": \"^4.1.4\"\n }\n}\n","import axios from 'axios';\r\nimport pkg from '../../package.json';\r\n\r\n/**\r\n * 로컬 패키지의 현재 버전을 반환합니다.\r\n */\r\nexport function getVersion(): string {\r\n return pkg.version;\r\n}\r\n\r\n/**\r\n * npm 레지스트리와 비교하여 최신 버전이 있는지 확인하고 콘솔에 알립니다.\r\n * 백그라운드에서 비동기로 실행됩니다.\r\n */\r\nexport async function checkVersion(): Promise<void> {\r\n try {\r\n const localVersion = pkg.version;\r\n const packageName = pkg.name; // 'cime-sdk'\r\n\r\n const { data, status } = await axios.get(`https://registry.npmjs.org/${packageName}/latest`, {\r\n timeout: 3000,\r\n });\r\n\r\n if (status !== 200 || !data || !data.version) {\r\n return;\r\n }\r\n\r\n const remoteVersion = data.version;\r\n\r\n if (isNewerVersion(localVersion, remoteVersion)) {\r\n console.log(`\\n======================================================`);\r\n console.log(`🚀 [CIME SDK] 새로운 버전을 찾았습니다!`);\r\n console.log(`현재 버전: ${localVersion} -> 최신 버전: ${remoteVersion}`);\r\n console.log(`UPDATE: npm install ${packageName}@${remoteVersion}`);\r\n console.log(`======================================================\\n`);\r\n }\r\n } catch (error) {\r\n return;\r\n }\r\n}\r\n\r\n/**\r\n * 두 버전 문자열을 비교합니다.\r\n * @returns remote가 local보다 크면 true\r\n */\r\nfunction isNewerVersion(local: string, remote: string): boolean {\r\n const lParts = local.split('.').map(Number);\r\n const rParts = remote.split('.').map(Number);\r\n\r\n const maxLength = Math.max(lParts.length, rParts.length);\r\n\r\n for (let i = 0; i < maxLength; i++) {\r\n const l = lParts[i] || 0;\r\n const r = rParts[i] || 0;\r\n \r\n if (r > l) return true;\r\n if (r < l) return false;\r\n }\r\n \r\n return false; // 완전히 동일한 버전\r\n}","import { CimeErrorResponse } from '../types';\r\n\r\n/**\r\n * ci.me API 요청 중 발생하는 에러를 캡슐화한 커스텀 에러 클래스입니다.\r\n * HTTP 상태 코드와 API가 반환한 상세 메시지를 포함합니다.\r\n */\r\nexport class CimeAPIError extends Error {\r\n public readonly statusCode: number;\r\n\r\n /**\r\n * @param errorResponse - API 서버에서 반환한 에러 객체\r\n */\r\n constructor(errorResponse: CimeErrorResponse) {\r\n super(errorResponse.message);\r\n this.name = 'CimeAPIError';\r\n this.statusCode = errorResponse.statusCode;\r\n\r\n // TypeScript 환경에서 Custom Error 생성 시 prototype 체인을 수동으로 복구 (instanceof 정상 작동을 위함)\r\n Object.setPrototypeOf(this, CimeAPIError.prototype);\r\n }\r\n}","import axios, { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios';\r\nimport axiosRetry from 'axios-retry';\r\nimport { CimeAPIError } from '../errors/CimeAPIError';\r\nimport { CimeCommonResponse, CimeErrorResponse, CimeClientOptions } from '../types';\r\nimport { getVersion } from './version';\r\n\r\n/**\r\n * 인증 정보와 기본 설정이 포함된 Axios 클라이언트 인스턴스를 생성합니다.\r\n */\r\nexport function createHttpClient(options: CimeClientOptions): AxiosInstance {\r\n const client = axios.create({\r\n baseURL: 'https://ci.me/api/openapi',\r\n timeout: options.timeout || 10000,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'User-Agent': `CimeSDK/${getVersion()} (Node)`,\r\n },\r\n });\r\n\r\n client.interceptors.request.use((config: InternalAxiosRequestConfig) => {\r\n if (options.accessToken) {\r\n config.headers['Authorization'] = `Bearer ${options.accessToken}`;\r\n }\r\n if (options.clientId && options.clientSecret) {\r\n config.headers['Client-Id'] = options.clientId;\r\n config.headers['Client-Secret'] = options.clientSecret;\r\n }\r\n return config;\r\n });\r\n\r\n axiosRetry(client, {\r\n retries: options.retries ?? 3,\r\n retryDelay: axiosRetry.exponentialDelay,\r\n retryCondition: (error: AxiosError) => {\r\n return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 500;\r\n },\r\n });\r\n\r\n client.interceptors.response.use(\r\n (response: AxiosResponse<CimeCommonResponse>) => {\r\n return response.data.content as any;\r\n },\r\n (error: AxiosError<CimeErrorResponse>) => {\r\n if (error.response && error.response.data) {\r\n throw new CimeAPIError(error.response.data);\r\n }\r\n throw error;\r\n }\r\n );\r\n\r\n return client;\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeTokenResponse } from '../types/auth';\r\n\r\nexport class AuthAPI {\r\n constructor(\r\n private readonly http: AxiosInstance,\r\n private readonly config: { clientId?: string; clientSecret?: string }\r\n ) {}\r\n\r\n /**\r\n * Authorization Code를 사용하여 Access Token과 Refresh Token을 발급받습니다.\r\n * @param code Redirect URI로 전달받은 인가 코드\r\n */\r\n public async get(code: string): Promise<CimeTokenResponse> {\r\n this.validateCredentials();\r\n\r\n const { data } = await this.http.post<CimeTokenResponse>('/auth/v1/token', {\r\n grantType: 'authorization_code',\r\n clientId: this.config.clientId,\r\n clientSecret: this.config.clientSecret,\r\n code\r\n });\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Refresh Token을 사용하여 Access Token을 갱신합니다.\r\n * @param refreshToken 이전에 발급받은 리프레시 토큰\r\n */\r\n public async refresh(refreshToken: string): Promise<CimeTokenResponse> {\r\n this.validateCredentials();\r\n\r\n const { data } = await this.http.post<CimeTokenResponse>('/auth/v1/token', {\r\n grantType: 'refresh_token',\r\n clientId: this.config.clientId,\r\n clientSecret: this.config.clientSecret,\r\n refreshToken\r\n });\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * 내부 헬퍼: 토큰 발급 시 필요한 Client ID 및 Secret 유효성 검사 (Fail-fast)\r\n */\r\n private validateCredentials(): void {\r\n if (!this.config.clientId || !this.config.clientSecret) {\r\n throw new Error(\r\n '[Cime SDK] OAuth 토큰을 발급/갱신하려면 초기화 시 clientId와 clientSecret이 필요합니다.'\r\n );\r\n }\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeUser, CimeClientOptions } from '../types';\r\n\r\n/**\r\n * 사용자(User) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class UsersAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 현재 Access Token에 연결된 사용자의 채널 정보를 조회합니다.\r\n *\r\n * @requires Scope: `READ:USER`\r\n * @throws {CimeAPIError} Access Token이 없거나 만료되었을 때 (401), 또는 권한이 부족할 때 발생합니다.\r\n * @returns 사용자의 채널 상세 정보\r\n * * @example\r\n * ```typescript\r\n * const me = await client.users.get();\r\n * console.log(`안녕하세요, ${me.channelName}님!`);\r\n * ```\r\n */\r\n public async get(): Promise<CimeUser> {\r\n if (!this.options.scopes?.includes('READ:USER')) {\r\n throw new Error('[UsersAPI] \"READ:USER\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // 인터셉터에서 response.data.content를 바로 반환하므로 리턴 타입은 CimeUser가 됩니다.\r\n return this.httpClient.get<any, CimeUser>('/open/v1/users/me');\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeDataList,\r\n CimeChannelInfo,\r\n CimeFollower,\r\n CimeChannelFollowersParams,\r\n CimeSubscriber,\r\n CimeChannelSubscribersParams,\r\n CimeManager,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 채널(Channel) 관련 API를 담당하는 클래스입니다.\r\n * 채널 정보, 팔로워, 구독자, 관리자 목록 조회 기능을 제공합니다.\r\n */\r\nexport class ChannelsAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 채널 ID 목록으로 채널의 기본 정보를 조회합니다. (최대 20개)\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param channelIds - 조회할 채널 ID 문자열 또는 ID 문자열의 배열\r\n * @returns 채널 정보 목록\r\n * * @example\r\n * ```typescript\r\n * const { data } = await client.channels.getChannels(['12345', '67890']);\r\n * ```\r\n */\r\n public async getChannels(channelIds: string | string[]): Promise<CimeDataList<CimeChannelInfo>> {\r\n // 배열이 들어올 경우 쉼표로 구분된 문자열로 자동 변환하여 편의성을 높입니다.\r\n const parsedIds = Array.isArray(channelIds) ? channelIds.join(',') : channelIds;\r\n \r\n return this.httpClient.get<any, CimeDataList<CimeChannelInfo>>('/open/v1/channels', {\r\n params: { channelIds: parsedIds },\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 팔로워 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:CHANNEL`\r\n * @param params - 페이징 파라미터 (page, size)\r\n * @returns 팔로워 목록\r\n */\r\n public async getFollowers(params?: CimeChannelFollowersParams): Promise<CimeDataList<CimeFollower>> {\r\n if (!this.options.scopes?.includes('READ:CHANNEL')) {\r\n throw new Error('[ChannelsAPI] \"READ:CHANNEL\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeFollower>>('/open/v1/channels/followers', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 구독자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:SUBSCRIPTION`\r\n * @param params - 페이징 및 정렬 파라미터 (page, size, sort)\r\n * @returns 구독자 목록\r\n */\r\n public async getSubscribers(params?: CimeChannelSubscribersParams): Promise<CimeDataList<CimeSubscriber>> {\r\n if (!this.options.scopes?.includes('READ:SUBSCRIPTION')) {\r\n throw new Error('[ChannelsAPI] \"READ:SUBSCRIPTION\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeSubscriber>>('/open/v1/channels/subscribers', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 관리자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:CHANNEL`\r\n * @returns 관리자 목록\r\n */\r\n public async getManagers(): Promise<CimeDataList<CimeManager>> {\r\n if (!this.options.scopes?.includes('READ:CHANNEL')) {\r\n throw new Error('[ChannelsAPI] \"READ:CHANNEL\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeManager>>('/open/v1/channels/streaming-roles');\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeCursorList,\r\n CimeLive,\r\n CimeLivesParams,\r\n CimeLiveSetting,\r\n CimeUpdateLiveSettingParams,\r\n CimeStreamKey,\r\n CimeLiveStatus,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 라이브(Live) 및 스트리밍 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class LiveAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 현재 진행 중인 라이브 방송 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param params - 커서 기반 페이징 파라미터 (size, next)\r\n * @returns 라이브 목록과 다음 페이지 커서 정보\r\n */\r\n public async getLives(params?: CimeLivesParams): Promise<CimeCursorList<CimeLive>> {\r\n return this.httpClient.get<any, CimeCursorList<CimeLive>>('/open/v1/lives', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 라이브 설정을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_STREAM_SETTINGS`\r\n * @returns 라이브 설정 정보\r\n */\r\n public async getSettings(): Promise<CimeLiveSetting> {\r\n if (!this.options.scopes?.includes('READ:LIVE_STREAM_SETTINGS')) {\r\n throw new Error('[LiveAPI] \"READ:LIVE_STREAM_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeLiveSetting>('/open/v1/lives/setting');\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 라이브 설정을 변경합니다. (전달된 필드만 업데이트)\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_STREAM_SETTINGS`\r\n * @param params - 변경할 라이브 설정 데이터\r\n */\r\n public async updateSettings(params: CimeUpdateLiveSettingParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_STREAM_SETTINGS')) {\r\n throw new Error('[LiveAPI] \"WRITE:LIVE_STREAM_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.patch('/open/v1/lives/setting', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 스트림 키(Stream Key)를 조회합니다.\r\n * OBS 등 외부 방송 도구 연동 시 사용됩니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_STREAM_KEY`\r\n * @returns 스트림 키\r\n */\r\n public async getStreamKey(): Promise<CimeStreamKey> {\r\n if (!this.options.scopes?.includes('READ:LIVE_STREAM_KEY')) {\r\n throw new Error('[LiveAPI] \"READ:LIVE_STREAM_KEY\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeStreamKey>('/open/v1/streams/key');\r\n }\r\n\r\n /**\r\n * 특정 채널의 라이브 방송 여부와 상태를 확인합니다.\r\n * 이 API는 인증 없이 호출할 수 있는 완전 공개 API입니다.\r\n *\r\n * @requires Auth: 불필요\r\n * @param channelId - 상태를 조회할 채널의 ID\r\n * @returns 라이브 상태 정보\r\n */\r\n public async getLiveStatus(channelId: string): Promise<CimeLiveStatus> {\r\n // 주의: 이 엔드포인트는 /open/v1/ 접두사 없이 /v1/ 으로 시작합니다.\r\n return this.httpClient.get<any, CimeLiveStatus>(`/v1/${channelId}/live-status`);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeChatSettings,\r\n CimeUpdateChatSettingsParams,\r\n CimeSendChatMessageParams,\r\n CimeSendChatMessageResponse,\r\n CimeRegisterChatNoticeParams,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 라이브 채팅(Chat) 설정 및 메시지 전송 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class ChatAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 인증된 사용자 채널의 채팅 설정을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_CHAT_SETTINGS`\r\n * @returns 채팅 설정 정보\r\n */\r\n public async getSettings(): Promise<CimeChatSettings> {\r\n if (!this.options.scopes?.includes('READ:LIVE_CHAT_SETTINGS')) {\r\n throw new Error('[ChatAPI] \"READ:LIVE_CHAT_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeChatSettings>('/open/v1/chats/settings');\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 채팅 설정을 변경합니다. (전달된 필드만 업데이트)\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT_SETTINGS`\r\n * @param params - 변경할 채팅 설정 데이터\r\n */\r\n public async updateSettings(params: CimeUpdateChatSettingsParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT_SETTINGS')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.put('/open/v1/chats/settings', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널 라이브 채팅에 메시지를 전송합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT`\r\n * @param params - 전송할 메시지 정보 및 발신자 타입\r\n * @returns 전송된 메시지 ID\r\n */\r\n public async sendMessage(params: CimeSendChatMessageParams): Promise<CimeSendChatMessageResponse> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.post<any, CimeSendChatMessageResponse>('/open/v1/chats/send', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널 라이브 채팅에 공지사항을 등록합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT_NOTICE`\r\n * @param params - 등록할 공지 메시지 내용 또는 기존 메시지 ID\r\n * @throws {Error} 파라미터가 모두 누락된 경우 서버 요청 전 사전 차단합니다.\r\n */\r\n public async registerNotice(params: CimeRegisterChatNoticeParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT_NOTICE')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT_NOTICE\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // Fail-fast 로직: 서버로 보내기 전 SDK 단에서 미리 파라미터 유효성 검사\r\n if (!params.message && !params.messageId) {\r\n throw new Error('[CimeClient.ChatAPI] registerNotice requires either \"message\" or \"messageId\".');\r\n }\r\n\r\n await this.httpClient.post('/open/v1/chats/notice', params);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeDataList, CimeCategory, CimeSearchCategoriesParams } from '../types';\r\n\r\n/**\r\n * 카테고리(Category) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class CategoriesAPI {\r\n constructor(private readonly httpClient: AxiosInstance) {}\r\n\r\n /**\r\n * 라이브 설정 등에 사용할 카테고리를 키워드로 검색합니다.\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param params - 검색 키워드 및 페이지 크기 파라미터\r\n * @returns 검색된 카테고리 목록\r\n */\r\n public async searchCategories(params?: CimeSearchCategoriesParams): Promise<CimeDataList<CimeCategory>> {\r\n return this.httpClient.get<any, CimeDataList<CimeCategory>>('/open/v1/categories/search', {\r\n params,\r\n });\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeCursorList,\r\n CimeRestrictUserParams,\r\n CimeGetRestrictedUsersParams,\r\n CimeRestrictedUser,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 사용자 차단 및 추방(Restrict) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class RestrictAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 특정 사용자를 추방합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:USER_BLOCK`\r\n * @param params - 추방할 대상 채널 ID\r\n */\r\n public async restrictUser(params: CimeRestrictUserParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"WRITE:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.post('/open/v1/restrict-channels', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 추방된 사용자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:USER_BLOCK`\r\n * @param params - 커서 기반 페이징 파라미터 (size, next)\r\n * @returns 추방된 사용자 목록\r\n */\r\n public async getRestrictedUsers(\r\n params?: CimeGetRestrictedUsersParams\r\n ): Promise<CimeCursorList<CimeRestrictedUser>> {\r\n if (!this.options.scopes?.includes('READ:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"READ:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeCursorList<CimeRestrictedUser>>('/open/v1/restrict-channels', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 특정 사용자의 추방을 해제합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:USER_BLOCK`\r\n * @param params - 추방 해제할 대상 채널 ID\r\n */\r\n public async unrestrictUser(params: CimeRestrictUserParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"WRITE:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // Axios에서 DELETE 요청에 Request Body를 담으려면 두 번째 인자인 config의 data 필드에 넣어야 합니다.\r\n await this.httpClient.delete('/open/v1/restrict-channels', {\r\n data: params,\r\n });\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeSessionResponse, CimeSessionType, CimeEventName } from '../types';\r\n\r\n/**\r\n * 세션(Session) 및 이벤트 구독 제어를 담당하는 클래스입니다.\r\n */\r\nexport class SessionsAPI {\r\n constructor(private readonly httpClient: AxiosInstance) {}\r\n\r\n /**\r\n * WebSocket 연결을 위한 새로운 세션을 생성합니다.\r\n *\r\n * @param type - 세션 유형 ('USER' 또는 'CLIENT')\r\n * @returns WebSocket URL을 포함한 세션 정보\r\n */\r\n public async createSession(type: CimeSessionType): Promise<CimeSessionResponse> {\r\n const endpoint = type === 'USER' ? '/open/v1/sessions/auth' : '/open/v1/sessions/auth/client';\r\n return this.httpClient.get<any, CimeSessionResponse>(endpoint);\r\n }\r\n\r\n /**\r\n * 특정 세션에 이벤트를 구독합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @param event - 구독할 이벤트 이름 (chat, donation, subscription)\r\n * @param sessionKey - 세션 키\r\n */\r\n public async subscribeEvent(event: CimeEventName, sessionKey: string): Promise<void> {\r\n await this.httpClient.post(`/open/v1/sessions/events/subscribe/${event}`, null, {\r\n params: { sessionKey },\r\n });\r\n }\r\n\r\n /**\r\n * 특정 세션에서 이벤트 구독을 해제합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @param event - 구독 해제할 이벤트 이름\r\n * @param sessionKey - 세션 키\r\n */\r\n public async unsubscribeEvent(event: CimeEventName, sessionKey: string): Promise<void> {\r\n await this.httpClient.post(`/open/v1/sessions/events/unsubscribe/${event}`, null, {\r\n params: { sessionKey },\r\n });\r\n }\r\n}","import WebSocket from 'ws';\r\nimport { EventEmitter } from 'events';\r\nimport { SessionsAPI } from '../api/sessions';\r\nimport { CimeEventClientOptions, CimeEventPayload } from '../types';\r\nimport { CimeChatEventData } from '../types/chat';\r\nimport { CimeDonationEventData } from '../types/donation';\r\nimport { CimeSubscriptionEventData } from '../types/subscription';\r\n\r\nexport type CimeLiveEventName = 'CHAT' | 'DONATION' | 'SUBSCRIPTION';\r\n\r\nexport declare interface CimeEventClient {\r\n on(event: 'CHAT', listener: (data: CimeChatEventData) => void): this;\r\n on(event: 'DONATION', listener: (data: CimeDonationEventData) => void): this;\r\n on(event: 'SUBSCRIPTION', listener: (data: CimeSubscriptionEventData) => void): this;\r\n \r\n on(event: 'connected', listener: () => void): this;\r\n on(event: 'disconnected', listener: () => void): this;\r\n on(event: 'error', listener: (error: Error) => void): this;\r\n on(event: 'reconnecting', listener: () => void): this;\r\n on(event: string | symbol, listener: (...args: any[]) => void): this;\r\n\r\n emit(event: 'CHAT', data: CimeChatEventData): boolean;\r\n emit(event: 'DONATION', data: CimeDonationEventData): boolean;\r\n emit(event: 'SUBSCRIPTION', data: CimeSubscriptionEventData): boolean;\r\n \r\n emit(event: 'connected'): boolean;\r\n emit(event: 'disconnected'): boolean;\r\n emit(event: 'error', error: Error): boolean;\r\n emit(event: 'reconnecting'): boolean;\r\n emit(event: string | symbol, ...args: any[]): boolean;\r\n}\r\n\r\n/**\r\n * ci.me API의 실시간 이벤트를 수신하기 위한 WebSocket 클라이언트입니다.\r\n */\r\nexport class CimeEventClient extends EventEmitter {\r\n private ws: WebSocket | null = null;\r\n private sessionKey: string | null = null;\r\n private pingTimer: NodeJS.Timeout | null = null;\r\n private reconnectTimer: NodeJS.Timeout | null = null;\r\n \r\n private isConnecting = false;\r\n private isIntentionalClose = false;\r\n \r\n private readonly activeSubscriptions = new Set<CimeLiveEventName>();\r\n\r\n constructor(\r\n private readonly sessionsApi: SessionsAPI,\r\n private readonly options: CimeEventClientOptions\r\n ) {\r\n super();\r\n }\r\n\r\n public async connect(): Promise<void> {\r\n if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) return;\r\n this.isConnecting = true;\r\n this.isIntentionalClose = false;\r\n\r\n try {\r\n const { url } = await this.sessionsApi.createSession(this.options.type);\r\n \r\n const parsedUrl = new URL(url);\r\n this.sessionKey = parsedUrl.searchParams.get('sessionKey');\r\n \r\n if (!this.sessionKey) {\r\n throw new Error('[CimeEventClient] Failed to extract sessionKey from URL.');\r\n }\r\n\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.on('open', async () => {\r\n this.isConnecting = false;\r\n this.startPing();\r\n this.emit('connected');\r\n\r\n for (const event of this.activeSubscriptions) {\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n await this.sessionsApi.subscribeEvent(apiEventName, this.sessionKey!).catch(err => {\r\n this.emit('error', new Error(`Failed to resubscribe ${event}: ${err.message}`));\r\n });\r\n }\r\n });\r\n\r\n this.ws.on('message', (data: WebSocket.RawData) => {\r\n this.handleMessage(data.toString());\r\n });\r\n\r\n this.ws.on('close', () => {\r\n this.cleanup();\r\n this.emit('disconnected');\r\n this.handleReconnect();\r\n });\r\n\r\n this.ws.on('error', (error) => {\r\n this.emit('error', error);\r\n });\r\n\r\n } catch (error) {\r\n this.isConnecting = false;\r\n this.emit('error', error as Error);\r\n this.handleReconnect(); \r\n }\r\n }\r\n\r\n /**\r\n * 실시간 이벤트를 구독합니다.\r\n * @param event - 'CHAT' | 'DONATION' | 'SUBSCRIPTION'\r\n */\r\n public async subscribe(event: CimeLiveEventName): Promise<void> {\r\n if (this.activeSubscriptions.size >= 30) {\r\n throw new Error('[CimeEventClient] Exceeded maximum 30 subscriptions per session.');\r\n }\r\n\r\n this.activeSubscriptions.add(event);\r\n \r\n // API 통신 시에는 소문자로 변환하여 전송합니다.\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n\r\n if (this.sessionKey && this.ws?.readyState === WebSocket.OPEN) {\r\n await this.sessionsApi.subscribeEvent(apiEventName, this.sessionKey);\r\n }\r\n }\r\n\r\n /**\r\n * 실시간 이벤트 구독을 해제합니다.\r\n * @param event - 'CHAT' | 'DONATION' | 'SUBSCRIPTION'\r\n */\r\n public async unsubscribe(event: CimeLiveEventName): Promise<void> {\r\n this.activeSubscriptions.delete(event);\r\n\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n\r\n if (this.sessionKey && this.ws?.readyState === WebSocket.OPEN) {\r\n await this.sessionsApi.unsubscribeEvent(apiEventName, this.sessionKey);\r\n }\r\n }\r\n\r\n public disconnect(): void {\r\n this.isIntentionalClose = true;\r\n this.activeSubscriptions.clear();\r\n this.cleanup();\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n }\r\n\r\n private handleMessage(message: string): void {\r\n try {\r\n const payload = JSON.parse(message);\r\n \r\n if (payload.action === 'PONG') return;\r\n\r\n if (payload.event && payload.data) {\r\n const typedPayload = payload as CimeEventPayload;\r\n this.emit(typedPayload.event as any, typedPayload.data);\r\n }\r\n } catch (error) {\r\n this.emit('error', new Error(`[CimeEventClient] Failed to parse message: ${message}`));\r\n }\r\n }\r\n\r\n private startPing(): void {\r\n const interval = this.options.pingInterval || 60000;\r\n this.pingTimer = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify({ type: 'PING' }));\r\n }\r\n }, interval);\r\n }\r\n\r\n private cleanup(): void {\r\n if (this.pingTimer) {\r\n clearInterval(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n this.isConnecting = false;\r\n }\r\n\r\n private async handleReconnect(): Promise<void> {\r\n if (this.isIntentionalClose) return;\r\n\r\n if (this.options.onTokenRefresh) {\r\n try {\r\n await this.options.onTokenRefresh();\r\n } catch (err) {\r\n this.emit('error', new Error('[CimeEventClient] Token refresh failed during reconnect.'));\r\n }\r\n }\r\n\r\n this.reconnectTimer = setTimeout(() => {\r\n this.emit('reconnecting');\r\n this.connect();\r\n }, 5000);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeClientOptions, CimeTokenResponse, CimeEventClientOptions } from './types';\r\nimport { createHttpClient } from './utils/httpClient';\r\nimport { AuthAPI } from './api/auth';\r\nimport { UsersAPI } from './api/users';\r\nimport { ChannelsAPI } from './api/channels';\r\nimport { LiveAPI } from './api/live';\r\nimport { ChatAPI } from './api/chat';\r\nimport { CategoriesAPI } from './api/categories';\r\nimport { RestrictAPI } from './api/restrict';\r\nimport { SessionsAPI } from './api/sessions';\r\nimport { CimeEventClient } from './ws/CimeEventClient';\r\n\r\n/**\r\n * ci.me API를 사용하기 위한 메인 클라이언트 클래스입니다.\r\n */\r\nexport class CimeClient {\r\n private readonly httpClient: AxiosInstance;\r\n private options: CimeClientOptions;\r\n\r\n public readonly auth: AuthAPI;\r\n public readonly users: UsersAPI;\r\n public readonly channels: ChannelsAPI;\r\n public readonly live: LiveAPI;\r\n public readonly chat: ChatAPI;\r\n public readonly categories: CategoriesAPI;\r\n public readonly restrict: RestrictAPI;\r\n public readonly sessions: SessionsAPI;\r\n\r\n constructor(options: CimeClientOptions) {\r\n // [버그 수정됨] accessToken이 없고, (clientId 또는 clientSecret이 없을 때) 에러를 발생시킵니다.\r\n if (!options.accessToken && (!options.clientId || !options.clientSecret)) {\r\n throw new Error('[CimeClient] Authentication credentials (accessToken OR clientId/Secret) are required.');\r\n }\r\n\r\n this.options = { ...options };\r\n this.httpClient = createHttpClient(this.options);\r\n\r\n this.auth = new AuthAPI(this.httpClient, { clientId: this.options.clientId, clientSecret: this.options.clientSecret });\r\n this.users = new UsersAPI(this.httpClient, this.options);\r\n this.channels = new ChannelsAPI(this.httpClient, this.options);\r\n this.live = new LiveAPI(this.httpClient, this.options);\r\n this.chat = new ChatAPI(this.httpClient, this.options);\r\n this.categories = new CategoriesAPI(this.httpClient);\r\n this.restrict = new RestrictAPI(this.httpClient, this.options);\r\n this.sessions = new SessionsAPI(this.httpClient);\r\n }\r\n\r\n public setAccessToken(token: string): void {\r\n this.options.accessToken = token;\r\n // httpClient 내부의 options 참조는 객체 참조이므로 속성만 바꿔주면 다음 요청부터 자동으로 반영됩니다.\r\n }\r\n\r\n /**\r\n * 실시간 이벤트를 수신하기 위한 WebSocket 클라이언트를 생성합니다.\r\n */\r\n public createEventClient(options: CimeEventClientOptions): CimeEventClient {\r\n if (options.refreshToken && !options.onTokenRefresh) {\r\n options.onTokenRefresh = async () => {\r\n try {\r\n const tokenInfo = await this.auth.refresh(options.refreshToken!);\r\n this.setAccessToken(tokenInfo.accessToken);\r\n options.refreshToken = tokenInfo.refreshToken;\r\n } catch (error) {\r\n throw new Error('자동 토큰 갱신에 실패했습니다.');\r\n }\r\n };\r\n }\r\n return new CimeEventClient(this.sessions, options);\r\n }\r\n\r\n /** * OAuth 인증 플로우를 통해 Access Token을 발급받고 클라이언트에 설정합니다.\r\n * @param code Redirect URI로 전달받은 인가 코드\r\n * @throws 인증 정보(clientId/Secret)가 없으면 에러를 반환합니다.\r\n */\r\n public async authorize(code: string): Promise<CimeTokenResponse> {\r\n if (!this.options.clientId || !this.options.clientSecret) {\r\n throw new Error('[CimeClient] OAuth authentication requires clientId and clientSecret to be set in options.');\r\n }\r\n\r\n const tokenResponse = await this.auth.get(code);\r\n this.setAccessToken(tokenResponse.accessToken);\r\n return tokenResponse;\r\n }\r\n}","import { CimeChatEventData } from '../types/chat';\r\n\r\n/**\r\n * 채팅 메시지 내의 이모티콘 토큰을 <img> 태그로 변환합니다.\r\n * 따로 UI를 만드실 계획이 아니시라면, 별 쓸모는 없습니다.\r\n * @param data 채팅 이벤트 데이터 (content, emojis)\r\n * @param className <img> 태그에 부여할 CSS 클래스명 (기본값: 'cime-emoji')\r\n * @returns 변환된 HTML 문자열\r\n */\r\nexport function renderChatEmojisToHTML(\r\n data: Pick<CimeChatEventData, 'content' | 'emojis'>,\r\n className: string = 'cime-emoji'\r\n): string {\r\n if (!data.emojis || Object.keys(data.emojis).length === 0) {\r\n return data.content;\r\n }\r\n\r\n let htmlMessage = data.content;\r\n\r\n for (const [token, imageUrl] of Object.entries(data.emojis)) {\r\n // 1. 토큰 내의 정규식 특수문자 안전하게 이스케이프 처리\r\n const escapedToken = token.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n const regex = new RegExp(escapedToken, 'g');\r\n\r\n // 2. replace의 두 번째 인자로 문자열 대신 '콜백 함수'를 사용하여\r\n // '$$' 기호가 단일 '$'로 치환되는 JavaScript 고유의 버그를 방지합니다.\r\n htmlMessage = htmlMessage.replace(regex, () => {\r\n return `<img src=\"${imageUrl}\" alt=\"${token}\" class=\"${className}\" />`;\r\n });\r\n }\r\n\r\n return htmlMessage;\r\n}","import { checkVersion } from './utils/version';\r\ncheckVersion();\r\n\r\nexport { CimeClient } from './client';\r\n\r\nexport { CimeAPIError } from './errors/CimeAPIError';\r\n\r\nexport { CimeEventClient, CimeLiveEventName } from './ws/CimeEventClient';\r\n\r\nexport * from './types';\r\n\r\nexport * from './utils/chatUtils';\r\nexport { getVersion } from './utils/version';"]}
package/dist/index.mjs CHANGED
@@ -8,7 +8,7 @@ import { EventEmitter } from 'events';
8
8
  // package.json
9
9
  var package_default = {
10
10
  name: "cime-sdk",
11
- version: "1.0.0",
11
+ version: "1.0.2",
12
12
  description: "A structural and object-oriented TypeScript SDK for ci.me API",
13
13
  main: "dist/index.js",
14
14
  module: "dist/index.mjs",
@@ -29,10 +29,17 @@ var package_default = {
29
29
  test: "vitest",
30
30
  typecheck: "tsc --noEmit"
31
31
  },
32
- keywords: ["cime", "sdk", "typescript"],
32
+ keywords: [
33
+ "cime",
34
+ "sdk",
35
+ "typescript"
36
+ ],
33
37
  author: "whitespaca",
34
38
  license: "MIT",
35
- repository: { type: "git", url: "https://github.com/whitespaca/cime-sdk" },
39
+ repository: {
40
+ type: "git",
41
+ url: "https://github.com/whitespaca/cime-sdk"
42
+ },
36
43
  type: "commonjs",
37
44
  dependencies: {
38
45
  axios: "^1.15.0",
@@ -158,7 +165,7 @@ var AuthAPI = class {
158
165
  */
159
166
  async get(code) {
160
167
  this.validateCredentials();
161
- const { data } = await this.http.post("/api/openapi/auth/v1/token", {
168
+ const { data } = await this.http.post("/auth/v1/token", {
162
169
  grantType: "authorization_code",
163
170
  clientId: this.config.clientId,
164
171
  clientSecret: this.config.clientSecret,
@@ -172,7 +179,7 @@ var AuthAPI = class {
172
179
  */
173
180
  async refresh(refreshToken) {
174
181
  this.validateCredentials();
175
- const { data } = await this.http.post("/api/openapi/auth/v1/token", {
182
+ const { data } = await this.http.post("/auth/v1/token", {
176
183
  grantType: "refresh_token",
177
184
  clientId: this.config.clientId,
178
185
  clientSecret: this.config.clientSecret,
@@ -1 +1 @@
1
- {"version":3,"sources":["../package.json","../src/utils/version.ts","../src/errors/CimeAPIError.ts","../src/utils/httpClient.ts","../src/api/auth.ts","../src/api/users.ts","../src/api/channels.ts","../src/api/live.ts","../src/api/chat.ts","../src/api/categories.ts","../src/api/restrict.ts","../src/api/sessions.ts","../src/ws/CimeEventClient.ts","../src/client.ts","../src/utils/chatUtils.ts","../src/index.ts"],"names":["axios"],"mappings":"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","file":"index.mjs","sourcesContent":["{\n \"name\": \"cime-sdk\",\n \"version\": \"1.0.0\",\n \"description\": \"A structural and object-oriented TypeScript SDK for ci.me API\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\"\n ],\n \"exports\": {\n \".\": {\n \"require\": \"./dist/index.js\",\n \"import\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.ts\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"keywords\": [\"cime\", \"sdk\", \"typescript\"],\n \"author\": \"whitespaca\",\n \"license\": \"MIT\",\n \"repository\": {\"type\": \"git\", \"url\": \"https://github.com/whitespaca/cime-sdk\" },\n \"type\": \"commonjs\",\n \"dependencies\": {\n \"axios\": \"^1.15.0\",\n \"axios-retry\": \"^4.5.0\",\n \"ws\": \"^8.20.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.6.0\",\n \"@types/ws\": \"^8.18.1\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.2\",\n \"vitest\": \"^4.1.4\"\n }\n}\n","import axios from 'axios';\r\nimport pkg from '../../package.json';\r\n\r\n/**\r\n * 로컬 패키지의 현재 버전을 반환합니다.\r\n */\r\nexport function getVersion(): string {\r\n return pkg.version;\r\n}\r\n\r\n/**\r\n * npm 레지스트리와 비교하여 최신 버전이 있는지 확인하고 콘솔에 알립니다.\r\n * 백그라운드에서 비동기로 실행됩니다.\r\n */\r\nexport async function checkVersion(): Promise<void> {\r\n try {\r\n const localVersion = pkg.version;\r\n const packageName = pkg.name; // 'cime-sdk'\r\n\r\n const { data, status } = await axios.get(`https://registry.npmjs.org/${packageName}/latest`, {\r\n timeout: 3000,\r\n });\r\n\r\n if (status !== 200 || !data || !data.version) {\r\n return;\r\n }\r\n\r\n const remoteVersion = data.version;\r\n\r\n if (isNewerVersion(localVersion, remoteVersion)) {\r\n console.log(`\\n======================================================`);\r\n console.log(`🚀 [CIME SDK] 새로운 버전을 찾았습니다!`);\r\n console.log(`현재 버전: ${localVersion} -> 최신 버전: ${remoteVersion}`);\r\n console.log(`UPDATE: npm install ${packageName}@${remoteVersion}`);\r\n console.log(`======================================================\\n`);\r\n }\r\n } catch (error) {\r\n return;\r\n }\r\n}\r\n\r\n/**\r\n * 두 버전 문자열을 비교합니다.\r\n * @returns remote가 local보다 크면 true\r\n */\r\nfunction isNewerVersion(local: string, remote: string): boolean {\r\n const lParts = local.split('.').map(Number);\r\n const rParts = remote.split('.').map(Number);\r\n\r\n const maxLength = Math.max(lParts.length, rParts.length);\r\n\r\n for (let i = 0; i < maxLength; i++) {\r\n const l = lParts[i] || 0;\r\n const r = rParts[i] || 0;\r\n \r\n if (r > l) return true;\r\n if (r < l) return false;\r\n }\r\n \r\n return false; // 완전히 동일한 버전\r\n}","import { CimeErrorResponse } from '../types';\r\n\r\n/**\r\n * ci.me API 요청 중 발생하는 에러를 캡슐화한 커스텀 에러 클래스입니다.\r\n * HTTP 상태 코드와 API가 반환한 상세 메시지를 포함합니다.\r\n */\r\nexport class CimeAPIError extends Error {\r\n public readonly statusCode: number;\r\n\r\n /**\r\n * @param errorResponse - API 서버에서 반환한 에러 객체\r\n */\r\n constructor(errorResponse: CimeErrorResponse) {\r\n super(errorResponse.message);\r\n this.name = 'CimeAPIError';\r\n this.statusCode = errorResponse.statusCode;\r\n\r\n // TypeScript 환경에서 Custom Error 생성 시 prototype 체인을 수동으로 복구 (instanceof 정상 작동을 위함)\r\n Object.setPrototypeOf(this, CimeAPIError.prototype);\r\n }\r\n}","import axios, { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios';\r\nimport axiosRetry from 'axios-retry';\r\nimport { CimeAPIError } from '../errors/CimeAPIError';\r\nimport { CimeCommonResponse, CimeErrorResponse, CimeClientOptions } from '../types';\r\nimport { getVersion } from './version';\r\n\r\n/**\r\n * 인증 정보와 기본 설정이 포함된 Axios 클라이언트 인스턴스를 생성합니다.\r\n */\r\nexport function createHttpClient(options: CimeClientOptions): AxiosInstance {\r\n const client = axios.create({\r\n baseURL: 'https://ci.me/api/openapi',\r\n timeout: options.timeout || 10000,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'User-Agent': `CimeSDK/${getVersion()} (Node)`,\r\n },\r\n });\r\n\r\n client.interceptors.request.use((config: InternalAxiosRequestConfig) => {\r\n if (options.accessToken) {\r\n config.headers['Authorization'] = `Bearer ${options.accessToken}`;\r\n }\r\n if (options.clientId && options.clientSecret) {\r\n config.headers['Client-Id'] = options.clientId;\r\n config.headers['Client-Secret'] = options.clientSecret;\r\n }\r\n return config;\r\n });\r\n\r\n axiosRetry(client, {\r\n retries: options.retries ?? 3,\r\n retryDelay: axiosRetry.exponentialDelay,\r\n retryCondition: (error: AxiosError) => {\r\n return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 500;\r\n },\r\n });\r\n\r\n client.interceptors.response.use(\r\n (response: AxiosResponse<CimeCommonResponse>) => {\r\n return response.data.content as any;\r\n },\r\n (error: AxiosError<CimeErrorResponse>) => {\r\n if (error.response && error.response.data) {\r\n throw new CimeAPIError(error.response.data);\r\n }\r\n throw error;\r\n }\r\n );\r\n\r\n return client;\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeTokenResponse } from '../types/auth';\r\n\r\nexport class AuthAPI {\r\n constructor(\r\n private readonly http: AxiosInstance,\r\n private readonly config: { clientId?: string; clientSecret?: string }\r\n ) {}\r\n\r\n /**\r\n * Authorization Code를 사용하여 Access Token과 Refresh Token을 발급받습니다.\r\n * @param code Redirect URI로 전달받은 인가 코드\r\n */\r\n public async get(code: string): Promise<CimeTokenResponse> {\r\n this.validateCredentials();\r\n\r\n const { data } = await this.http.post<CimeTokenResponse>('/api/openapi/auth/v1/token', {\r\n grantType: 'authorization_code',\r\n clientId: this.config.clientId,\r\n clientSecret: this.config.clientSecret,\r\n code\r\n });\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Refresh Token을 사용하여 Access Token을 갱신합니다.\r\n * @param refreshToken 이전에 발급받은 리프레시 토큰\r\n */\r\n public async refresh(refreshToken: string): Promise<CimeTokenResponse> {\r\n this.validateCredentials();\r\n\r\n const { data } = await this.http.post<CimeTokenResponse>('/api/openapi/auth/v1/token', {\r\n grantType: 'refresh_token',\r\n clientId: this.config.clientId,\r\n clientSecret: this.config.clientSecret,\r\n refreshToken\r\n });\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * 내부 헬퍼: 토큰 발급 시 필요한 Client ID 및 Secret 유효성 검사 (Fail-fast)\r\n */\r\n private validateCredentials(): void {\r\n if (!this.config.clientId || !this.config.clientSecret) {\r\n throw new Error(\r\n '[Cime SDK] OAuth 토큰을 발급/갱신하려면 초기화 시 clientId와 clientSecret이 필요합니다.'\r\n );\r\n }\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeUser, CimeClientOptions } from '../types';\r\n\r\n/**\r\n * 사용자(User) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class UsersAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 현재 Access Token에 연결된 사용자의 채널 정보를 조회합니다.\r\n *\r\n * @requires Scope: `READ:USER`\r\n * @throws {CimeAPIError} Access Token이 없거나 만료되었을 때 (401), 또는 권한이 부족할 때 발생합니다.\r\n * @returns 사용자의 채널 상세 정보\r\n * * @example\r\n * ```typescript\r\n * const me = await client.users.get();\r\n * console.log(`안녕하세요, ${me.channelName}님!`);\r\n * ```\r\n */\r\n public async get(): Promise<CimeUser> {\r\n if (!this.options.scopes?.includes('READ:USER')) {\r\n throw new Error('[UsersAPI] \"READ:USER\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // 인터셉터에서 response.data.content를 바로 반환하므로 리턴 타입은 CimeUser가 됩니다.\r\n return this.httpClient.get<any, CimeUser>('/open/v1/users/me');\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeDataList,\r\n CimeChannelInfo,\r\n CimeFollower,\r\n CimeChannelFollowersParams,\r\n CimeSubscriber,\r\n CimeChannelSubscribersParams,\r\n CimeManager,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 채널(Channel) 관련 API를 담당하는 클래스입니다.\r\n * 채널 정보, 팔로워, 구독자, 관리자 목록 조회 기능을 제공합니다.\r\n */\r\nexport class ChannelsAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 채널 ID 목록으로 채널의 기본 정보를 조회합니다. (최대 20개)\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param channelIds - 조회할 채널 ID 문자열 또는 ID 문자열의 배열\r\n * @returns 채널 정보 목록\r\n * * @example\r\n * ```typescript\r\n * const { data } = await client.channels.getChannels(['12345', '67890']);\r\n * ```\r\n */\r\n public async getChannels(channelIds: string | string[]): Promise<CimeDataList<CimeChannelInfo>> {\r\n // 배열이 들어올 경우 쉼표로 구분된 문자열로 자동 변환하여 편의성을 높입니다.\r\n const parsedIds = Array.isArray(channelIds) ? channelIds.join(',') : channelIds;\r\n \r\n return this.httpClient.get<any, CimeDataList<CimeChannelInfo>>('/open/v1/channels', {\r\n params: { channelIds: parsedIds },\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 팔로워 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:CHANNEL`\r\n * @param params - 페이징 파라미터 (page, size)\r\n * @returns 팔로워 목록\r\n */\r\n public async getFollowers(params?: CimeChannelFollowersParams): Promise<CimeDataList<CimeFollower>> {\r\n if (!this.options.scopes?.includes('READ:CHANNEL')) {\r\n throw new Error('[ChannelsAPI] \"READ:CHANNEL\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeFollower>>('/open/v1/channels/followers', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 구독자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:SUBSCRIPTION`\r\n * @param params - 페이징 및 정렬 파라미터 (page, size, sort)\r\n * @returns 구독자 목록\r\n */\r\n public async getSubscribers(params?: CimeChannelSubscribersParams): Promise<CimeDataList<CimeSubscriber>> {\r\n if (!this.options.scopes?.includes('READ:SUBSCRIPTION')) {\r\n throw new Error('[ChannelsAPI] \"READ:SUBSCRIPTION\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeSubscriber>>('/open/v1/channels/subscribers', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 관리자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:CHANNEL`\r\n * @returns 관리자 목록\r\n */\r\n public async getManagers(): Promise<CimeDataList<CimeManager>> {\r\n if (!this.options.scopes?.includes('READ:CHANNEL')) {\r\n throw new Error('[ChannelsAPI] \"READ:CHANNEL\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeManager>>('/open/v1/channels/streaming-roles');\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeCursorList,\r\n CimeLive,\r\n CimeLivesParams,\r\n CimeLiveSetting,\r\n CimeUpdateLiveSettingParams,\r\n CimeStreamKey,\r\n CimeLiveStatus,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 라이브(Live) 및 스트리밍 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class LiveAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 현재 진행 중인 라이브 방송 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param params - 커서 기반 페이징 파라미터 (size, next)\r\n * @returns 라이브 목록과 다음 페이지 커서 정보\r\n */\r\n public async getLives(params?: CimeLivesParams): Promise<CimeCursorList<CimeLive>> {\r\n return this.httpClient.get<any, CimeCursorList<CimeLive>>('/open/v1/lives', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 라이브 설정을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_STREAM_SETTINGS`\r\n * @returns 라이브 설정 정보\r\n */\r\n public async getSettings(): Promise<CimeLiveSetting> {\r\n if (!this.options.scopes?.includes('READ:LIVE_STREAM_SETTINGS')) {\r\n throw new Error('[LiveAPI] \"READ:LIVE_STREAM_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeLiveSetting>('/open/v1/lives/setting');\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 라이브 설정을 변경합니다. (전달된 필드만 업데이트)\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_STREAM_SETTINGS`\r\n * @param params - 변경할 라이브 설정 데이터\r\n */\r\n public async updateSettings(params: CimeUpdateLiveSettingParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_STREAM_SETTINGS')) {\r\n throw new Error('[LiveAPI] \"WRITE:LIVE_STREAM_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.patch('/open/v1/lives/setting', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 스트림 키(Stream Key)를 조회합니다.\r\n * OBS 등 외부 방송 도구 연동 시 사용됩니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_STREAM_KEY`\r\n * @returns 스트림 키\r\n */\r\n public async getStreamKey(): Promise<CimeStreamKey> {\r\n if (!this.options.scopes?.includes('READ:LIVE_STREAM_KEY')) {\r\n throw new Error('[LiveAPI] \"READ:LIVE_STREAM_KEY\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeStreamKey>('/open/v1/streams/key');\r\n }\r\n\r\n /**\r\n * 특정 채널의 라이브 방송 여부와 상태를 확인합니다.\r\n * 이 API는 인증 없이 호출할 수 있는 완전 공개 API입니다.\r\n *\r\n * @requires Auth: 불필요\r\n * @param channelId - 상태를 조회할 채널의 ID\r\n * @returns 라이브 상태 정보\r\n */\r\n public async getLiveStatus(channelId: string): Promise<CimeLiveStatus> {\r\n // 주의: 이 엔드포인트는 /open/v1/ 접두사 없이 /v1/ 으로 시작합니다.\r\n return this.httpClient.get<any, CimeLiveStatus>(`/v1/${channelId}/live-status`);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeChatSettings,\r\n CimeUpdateChatSettingsParams,\r\n CimeSendChatMessageParams,\r\n CimeSendChatMessageResponse,\r\n CimeRegisterChatNoticeParams,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 라이브 채팅(Chat) 설정 및 메시지 전송 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class ChatAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 인증된 사용자 채널의 채팅 설정을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_CHAT_SETTINGS`\r\n * @returns 채팅 설정 정보\r\n */\r\n public async getSettings(): Promise<CimeChatSettings> {\r\n if (!this.options.scopes?.includes('READ:LIVE_CHAT_SETTINGS')) {\r\n throw new Error('[ChatAPI] \"READ:LIVE_CHAT_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeChatSettings>('/open/v1/chats/settings');\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 채팅 설정을 변경합니다. (전달된 필드만 업데이트)\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT_SETTINGS`\r\n * @param params - 변경할 채팅 설정 데이터\r\n */\r\n public async updateSettings(params: CimeUpdateChatSettingsParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT_SETTINGS')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.put('/open/v1/chats/settings', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널 라이브 채팅에 메시지를 전송합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT`\r\n * @param params - 전송할 메시지 정보 및 발신자 타입\r\n * @returns 전송된 메시지 ID\r\n */\r\n public async sendMessage(params: CimeSendChatMessageParams): Promise<CimeSendChatMessageResponse> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.post<any, CimeSendChatMessageResponse>('/open/v1/chats/send', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널 라이브 채팅에 공지사항을 등록합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT_NOTICE`\r\n * @param params - 등록할 공지 메시지 내용 또는 기존 메시지 ID\r\n * @throws {Error} 파라미터가 모두 누락된 경우 서버 요청 전 사전 차단합니다.\r\n */\r\n public async registerNotice(params: CimeRegisterChatNoticeParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT_NOTICE')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT_NOTICE\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // Fail-fast 로직: 서버로 보내기 전 SDK 단에서 미리 파라미터 유효성 검사\r\n if (!params.message && !params.messageId) {\r\n throw new Error('[CimeClient.ChatAPI] registerNotice requires either \"message\" or \"messageId\".');\r\n }\r\n\r\n await this.httpClient.post('/open/v1/chats/notice', params);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeDataList, CimeCategory, CimeSearchCategoriesParams } from '../types';\r\n\r\n/**\r\n * 카테고리(Category) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class CategoriesAPI {\r\n constructor(private readonly httpClient: AxiosInstance) {}\r\n\r\n /**\r\n * 라이브 설정 등에 사용할 카테고리를 키워드로 검색합니다.\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param params - 검색 키워드 및 페이지 크기 파라미터\r\n * @returns 검색된 카테고리 목록\r\n */\r\n public async searchCategories(params?: CimeSearchCategoriesParams): Promise<CimeDataList<CimeCategory>> {\r\n return this.httpClient.get<any, CimeDataList<CimeCategory>>('/open/v1/categories/search', {\r\n params,\r\n });\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeCursorList,\r\n CimeRestrictUserParams,\r\n CimeGetRestrictedUsersParams,\r\n CimeRestrictedUser,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 사용자 차단 및 추방(Restrict) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class RestrictAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 특정 사용자를 추방합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:USER_BLOCK`\r\n * @param params - 추방할 대상 채널 ID\r\n */\r\n public async restrictUser(params: CimeRestrictUserParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"WRITE:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.post('/open/v1/restrict-channels', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 추방된 사용자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:USER_BLOCK`\r\n * @param params - 커서 기반 페이징 파라미터 (size, next)\r\n * @returns 추방된 사용자 목록\r\n */\r\n public async getRestrictedUsers(\r\n params?: CimeGetRestrictedUsersParams\r\n ): Promise<CimeCursorList<CimeRestrictedUser>> {\r\n if (!this.options.scopes?.includes('READ:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"READ:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeCursorList<CimeRestrictedUser>>('/open/v1/restrict-channels', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 특정 사용자의 추방을 해제합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:USER_BLOCK`\r\n * @param params - 추방 해제할 대상 채널 ID\r\n */\r\n public async unrestrictUser(params: CimeRestrictUserParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"WRITE:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // Axios에서 DELETE 요청에 Request Body를 담으려면 두 번째 인자인 config의 data 필드에 넣어야 합니다.\r\n await this.httpClient.delete('/open/v1/restrict-channels', {\r\n data: params,\r\n });\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeSessionResponse, CimeSessionType, CimeEventName } from '../types';\r\n\r\n/**\r\n * 세션(Session) 및 이벤트 구독 제어를 담당하는 클래스입니다.\r\n */\r\nexport class SessionsAPI {\r\n constructor(private readonly httpClient: AxiosInstance) {}\r\n\r\n /**\r\n * WebSocket 연결을 위한 새로운 세션을 생성합니다.\r\n *\r\n * @param type - 세션 유형 ('USER' 또는 'CLIENT')\r\n * @returns WebSocket URL을 포함한 세션 정보\r\n */\r\n public async createSession(type: CimeSessionType): Promise<CimeSessionResponse> {\r\n const endpoint = type === 'USER' ? '/open/v1/sessions/auth' : '/open/v1/sessions/auth/client';\r\n return this.httpClient.get<any, CimeSessionResponse>(endpoint);\r\n }\r\n\r\n /**\r\n * 특정 세션에 이벤트를 구독합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @param event - 구독할 이벤트 이름 (chat, donation, subscription)\r\n * @param sessionKey - 세션 키\r\n */\r\n public async subscribeEvent(event: CimeEventName, sessionKey: string): Promise<void> {\r\n await this.httpClient.post(`/open/v1/sessions/events/subscribe/${event}`, null, {\r\n params: { sessionKey },\r\n });\r\n }\r\n\r\n /**\r\n * 특정 세션에서 이벤트 구독을 해제합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @param event - 구독 해제할 이벤트 이름\r\n * @param sessionKey - 세션 키\r\n */\r\n public async unsubscribeEvent(event: CimeEventName, sessionKey: string): Promise<void> {\r\n await this.httpClient.post(`/open/v1/sessions/events/unsubscribe/${event}`, null, {\r\n params: { sessionKey },\r\n });\r\n }\r\n}","import WebSocket from 'ws';\r\nimport { EventEmitter } from 'events';\r\nimport { SessionsAPI } from '../api/sessions';\r\nimport { CimeEventClientOptions, CimeEventPayload } from '../types';\r\nimport { CimeChatEventData } from '../types/chat';\r\nimport { CimeDonationEventData } from '../types/donation';\r\nimport { CimeSubscriptionEventData } from '../types/subscription';\r\n\r\nexport type CimeLiveEventName = 'CHAT' | 'DONATION' | 'SUBSCRIPTION';\r\n\r\nexport declare interface CimeEventClient {\r\n on(event: 'CHAT', listener: (data: CimeChatEventData) => void): this;\r\n on(event: 'DONATION', listener: (data: CimeDonationEventData) => void): this;\r\n on(event: 'SUBSCRIPTION', listener: (data: CimeSubscriptionEventData) => void): this;\r\n \r\n on(event: 'connected', listener: () => void): this;\r\n on(event: 'disconnected', listener: () => void): this;\r\n on(event: 'error', listener: (error: Error) => void): this;\r\n on(event: 'reconnecting', listener: () => void): this;\r\n on(event: string | symbol, listener: (...args: any[]) => void): this;\r\n\r\n emit(event: 'CHAT', data: CimeChatEventData): boolean;\r\n emit(event: 'DONATION', data: CimeDonationEventData): boolean;\r\n emit(event: 'SUBSCRIPTION', data: CimeSubscriptionEventData): boolean;\r\n \r\n emit(event: 'connected'): boolean;\r\n emit(event: 'disconnected'): boolean;\r\n emit(event: 'error', error: Error): boolean;\r\n emit(event: 'reconnecting'): boolean;\r\n emit(event: string | symbol, ...args: any[]): boolean;\r\n}\r\n\r\n/**\r\n * ci.me API의 실시간 이벤트를 수신하기 위한 WebSocket 클라이언트입니다.\r\n */\r\nexport class CimeEventClient extends EventEmitter {\r\n private ws: WebSocket | null = null;\r\n private sessionKey: string | null = null;\r\n private pingTimer: NodeJS.Timeout | null = null;\r\n private reconnectTimer: NodeJS.Timeout | null = null;\r\n \r\n private isConnecting = false;\r\n private isIntentionalClose = false;\r\n \r\n private readonly activeSubscriptions = new Set<CimeLiveEventName>();\r\n\r\n constructor(\r\n private readonly sessionsApi: SessionsAPI,\r\n private readonly options: CimeEventClientOptions\r\n ) {\r\n super();\r\n }\r\n\r\n public async connect(): Promise<void> {\r\n if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) return;\r\n this.isConnecting = true;\r\n this.isIntentionalClose = false;\r\n\r\n try {\r\n const { url } = await this.sessionsApi.createSession(this.options.type);\r\n \r\n const parsedUrl = new URL(url);\r\n this.sessionKey = parsedUrl.searchParams.get('sessionKey');\r\n \r\n if (!this.sessionKey) {\r\n throw new Error('[CimeEventClient] Failed to extract sessionKey from URL.');\r\n }\r\n\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.on('open', async () => {\r\n this.isConnecting = false;\r\n this.startPing();\r\n this.emit('connected');\r\n\r\n for (const event of this.activeSubscriptions) {\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n await this.sessionsApi.subscribeEvent(apiEventName, this.sessionKey!).catch(err => {\r\n this.emit('error', new Error(`Failed to resubscribe ${event}: ${err.message}`));\r\n });\r\n }\r\n });\r\n\r\n this.ws.on('message', (data: WebSocket.RawData) => {\r\n this.handleMessage(data.toString());\r\n });\r\n\r\n this.ws.on('close', () => {\r\n this.cleanup();\r\n this.emit('disconnected');\r\n this.handleReconnect();\r\n });\r\n\r\n this.ws.on('error', (error) => {\r\n this.emit('error', error);\r\n });\r\n\r\n } catch (error) {\r\n this.isConnecting = false;\r\n this.emit('error', error as Error);\r\n this.handleReconnect(); \r\n }\r\n }\r\n\r\n /**\r\n * 실시간 이벤트를 구독합니다.\r\n * @param event - 'CHAT' | 'DONATION' | 'SUBSCRIPTION'\r\n */\r\n public async subscribe(event: CimeLiveEventName): Promise<void> {\r\n if (this.activeSubscriptions.size >= 30) {\r\n throw new Error('[CimeEventClient] Exceeded maximum 30 subscriptions per session.');\r\n }\r\n\r\n this.activeSubscriptions.add(event);\r\n \r\n // API 통신 시에는 소문자로 변환하여 전송합니다.\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n\r\n if (this.sessionKey && this.ws?.readyState === WebSocket.OPEN) {\r\n await this.sessionsApi.subscribeEvent(apiEventName, this.sessionKey);\r\n }\r\n }\r\n\r\n /**\r\n * 실시간 이벤트 구독을 해제합니다.\r\n * @param event - 'CHAT' | 'DONATION' | 'SUBSCRIPTION'\r\n */\r\n public async unsubscribe(event: CimeLiveEventName): Promise<void> {\r\n this.activeSubscriptions.delete(event);\r\n\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n\r\n if (this.sessionKey && this.ws?.readyState === WebSocket.OPEN) {\r\n await this.sessionsApi.unsubscribeEvent(apiEventName, this.sessionKey);\r\n }\r\n }\r\n\r\n public disconnect(): void {\r\n this.isIntentionalClose = true;\r\n this.activeSubscriptions.clear();\r\n this.cleanup();\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n }\r\n\r\n private handleMessage(message: string): void {\r\n try {\r\n const payload = JSON.parse(message);\r\n \r\n if (payload.action === 'PONG') return;\r\n\r\n if (payload.event && payload.data) {\r\n const typedPayload = payload as CimeEventPayload;\r\n this.emit(typedPayload.event as any, typedPayload.data);\r\n }\r\n } catch (error) {\r\n this.emit('error', new Error(`[CimeEventClient] Failed to parse message: ${message}`));\r\n }\r\n }\r\n\r\n private startPing(): void {\r\n const interval = this.options.pingInterval || 60000;\r\n this.pingTimer = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify({ type: 'PING' }));\r\n }\r\n }, interval);\r\n }\r\n\r\n private cleanup(): void {\r\n if (this.pingTimer) {\r\n clearInterval(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n this.isConnecting = false;\r\n }\r\n\r\n private async handleReconnect(): Promise<void> {\r\n if (this.isIntentionalClose) return;\r\n\r\n if (this.options.onTokenRefresh) {\r\n try {\r\n await this.options.onTokenRefresh();\r\n } catch (err) {\r\n this.emit('error', new Error('[CimeEventClient] Token refresh failed during reconnect.'));\r\n }\r\n }\r\n\r\n this.reconnectTimer = setTimeout(() => {\r\n this.emit('reconnecting');\r\n this.connect();\r\n }, 5000);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeClientOptions, CimeTokenResponse, CimeEventClientOptions } from './types';\r\nimport { createHttpClient } from './utils/httpClient';\r\nimport { AuthAPI } from './api/auth';\r\nimport { UsersAPI } from './api/users';\r\nimport { ChannelsAPI } from './api/channels';\r\nimport { LiveAPI } from './api/live';\r\nimport { ChatAPI } from './api/chat';\r\nimport { CategoriesAPI } from './api/categories';\r\nimport { RestrictAPI } from './api/restrict';\r\nimport { SessionsAPI } from './api/sessions';\r\nimport { CimeEventClient } from './ws/CimeEventClient';\r\n\r\n/**\r\n * ci.me API를 사용하기 위한 메인 클라이언트 클래스입니다.\r\n */\r\nexport class CimeClient {\r\n private readonly httpClient: AxiosInstance;\r\n private options: CimeClientOptions;\r\n\r\n public readonly auth: AuthAPI;\r\n public readonly users: UsersAPI;\r\n public readonly channels: ChannelsAPI;\r\n public readonly live: LiveAPI;\r\n public readonly chat: ChatAPI;\r\n public readonly categories: CategoriesAPI;\r\n public readonly restrict: RestrictAPI;\r\n public readonly sessions: SessionsAPI;\r\n\r\n constructor(options: CimeClientOptions) {\r\n // [버그 수정됨] accessToken이 없고, (clientId 또는 clientSecret이 없을 때) 에러를 발생시킵니다.\r\n if (!options.accessToken && (!options.clientId || !options.clientSecret)) {\r\n throw new Error('[CimeClient] Authentication credentials (accessToken OR clientId/Secret) are required.');\r\n }\r\n\r\n this.options = { ...options };\r\n this.httpClient = createHttpClient(this.options);\r\n\r\n this.auth = new AuthAPI(this.httpClient, { clientId: this.options.clientId, clientSecret: this.options.clientSecret });\r\n this.users = new UsersAPI(this.httpClient, this.options);\r\n this.channels = new ChannelsAPI(this.httpClient, this.options);\r\n this.live = new LiveAPI(this.httpClient, this.options);\r\n this.chat = new ChatAPI(this.httpClient, this.options);\r\n this.categories = new CategoriesAPI(this.httpClient);\r\n this.restrict = new RestrictAPI(this.httpClient, this.options);\r\n this.sessions = new SessionsAPI(this.httpClient);\r\n }\r\n\r\n public setAccessToken(token: string): void {\r\n this.options.accessToken = token;\r\n // httpClient 내부의 options 참조는 객체 참조이므로 속성만 바꿔주면 다음 요청부터 자동으로 반영됩니다.\r\n }\r\n\r\n /**\r\n * 실시간 이벤트를 수신하기 위한 WebSocket 클라이언트를 생성합니다.\r\n */\r\n public createEventClient(options: CimeEventClientOptions): CimeEventClient {\r\n if (options.refreshToken && !options.onTokenRefresh) {\r\n options.onTokenRefresh = async () => {\r\n try {\r\n const tokenInfo = await this.auth.refresh(options.refreshToken!);\r\n this.setAccessToken(tokenInfo.accessToken);\r\n options.refreshToken = tokenInfo.refreshToken;\r\n } catch (error) {\r\n throw new Error('자동 토큰 갱신에 실패했습니다.');\r\n }\r\n };\r\n }\r\n return new CimeEventClient(this.sessions, options);\r\n }\r\n\r\n /** * OAuth 인증 플로우를 통해 Access Token을 발급받고 클라이언트에 설정합니다.\r\n * @param code Redirect URI로 전달받은 인가 코드\r\n * @throws 인증 정보(clientId/Secret)가 없으면 에러를 반환합니다.\r\n */\r\n public async authorize(code: string): Promise<CimeTokenResponse> {\r\n if (!this.options.clientId || !this.options.clientSecret) {\r\n throw new Error('[CimeClient] OAuth authentication requires clientId and clientSecret to be set in options.');\r\n }\r\n\r\n const tokenResponse = await this.auth.get(code);\r\n this.setAccessToken(tokenResponse.accessToken);\r\n return tokenResponse;\r\n }\r\n}","import { CimeChatEventData } from '../types/chat';\r\n\r\n/**\r\n * 채팅 메시지 내의 이모티콘 토큰을 <img> 태그로 변환합니다.\r\n * 따로 UI를 만드실 계획이 아니시라면, 별 쓸모는 없습니다.\r\n * @param data 채팅 이벤트 데이터 (content, emojis)\r\n * @param className <img> 태그에 부여할 CSS 클래스명 (기본값: 'cime-emoji')\r\n * @returns 변환된 HTML 문자열\r\n */\r\nexport function renderChatEmojisToHTML(\r\n data: Pick<CimeChatEventData, 'content' | 'emojis'>,\r\n className: string = 'cime-emoji'\r\n): string {\r\n if (!data.emojis || Object.keys(data.emojis).length === 0) {\r\n return data.content;\r\n }\r\n\r\n let htmlMessage = data.content;\r\n\r\n for (const [token, imageUrl] of Object.entries(data.emojis)) {\r\n // 1. 토큰 내의 정규식 특수문자 안전하게 이스케이프 처리\r\n const escapedToken = token.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n const regex = new RegExp(escapedToken, 'g');\r\n\r\n // 2. replace의 두 번째 인자로 문자열 대신 '콜백 함수'를 사용하여\r\n // '$$' 기호가 단일 '$'로 치환되는 JavaScript 고유의 버그를 방지합니다.\r\n htmlMessage = htmlMessage.replace(regex, () => {\r\n return `<img src=\"${imageUrl}\" alt=\"${token}\" class=\"${className}\" />`;\r\n });\r\n }\r\n\r\n return htmlMessage;\r\n}","import { checkVersion } from './utils/version';\r\ncheckVersion();\r\n\r\nexport { CimeClient } from './client';\r\n\r\nexport { CimeAPIError } from './errors/CimeAPIError';\r\n\r\nexport { CimeEventClient, CimeLiveEventName } from './ws/CimeEventClient';\r\n\r\nexport * from './types';\r\n\r\nexport * from './utils/chatUtils';\r\nexport { getVersion } from './utils/version';"]}
1
+ {"version":3,"sources":["../package.json","../src/utils/version.ts","../src/errors/CimeAPIError.ts","../src/utils/httpClient.ts","../src/api/auth.ts","../src/api/users.ts","../src/api/channels.ts","../src/api/live.ts","../src/api/chat.ts","../src/api/categories.ts","../src/api/restrict.ts","../src/api/sessions.ts","../src/ws/CimeEventClient.ts","../src/client.ts","../src/utils/chatUtils.ts","../src/index.ts"],"names":["axios"],"mappings":"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","file":"index.mjs","sourcesContent":["{\n \"name\": \"cime-sdk\",\n \"version\": \"1.0.2\",\n \"description\": \"A structural and object-oriented TypeScript SDK for ci.me API\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\"\n ],\n \"exports\": {\n \".\": {\n \"require\": \"./dist/index.js\",\n \"import\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.ts\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"keywords\": [\n \"cime\",\n \"sdk\",\n \"typescript\"\n ],\n \"author\": \"whitespaca\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/whitespaca/cime-sdk\"\n },\n \"type\": \"commonjs\",\n \"dependencies\": {\n \"axios\": \"^1.15.0\",\n \"axios-retry\": \"^4.5.0\",\n \"ws\": \"^8.20.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.6.0\",\n \"@types/ws\": \"^8.18.1\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.2\",\n \"vitest\": \"^4.1.4\"\n }\n}\n","import axios from 'axios';\r\nimport pkg from '../../package.json';\r\n\r\n/**\r\n * 로컬 패키지의 현재 버전을 반환합니다.\r\n */\r\nexport function getVersion(): string {\r\n return pkg.version;\r\n}\r\n\r\n/**\r\n * npm 레지스트리와 비교하여 최신 버전이 있는지 확인하고 콘솔에 알립니다.\r\n * 백그라운드에서 비동기로 실행됩니다.\r\n */\r\nexport async function checkVersion(): Promise<void> {\r\n try {\r\n const localVersion = pkg.version;\r\n const packageName = pkg.name; // 'cime-sdk'\r\n\r\n const { data, status } = await axios.get(`https://registry.npmjs.org/${packageName}/latest`, {\r\n timeout: 3000,\r\n });\r\n\r\n if (status !== 200 || !data || !data.version) {\r\n return;\r\n }\r\n\r\n const remoteVersion = data.version;\r\n\r\n if (isNewerVersion(localVersion, remoteVersion)) {\r\n console.log(`\\n======================================================`);\r\n console.log(`🚀 [CIME SDK] 새로운 버전을 찾았습니다!`);\r\n console.log(`현재 버전: ${localVersion} -> 최신 버전: ${remoteVersion}`);\r\n console.log(`UPDATE: npm install ${packageName}@${remoteVersion}`);\r\n console.log(`======================================================\\n`);\r\n }\r\n } catch (error) {\r\n return;\r\n }\r\n}\r\n\r\n/**\r\n * 두 버전 문자열을 비교합니다.\r\n * @returns remote가 local보다 크면 true\r\n */\r\nfunction isNewerVersion(local: string, remote: string): boolean {\r\n const lParts = local.split('.').map(Number);\r\n const rParts = remote.split('.').map(Number);\r\n\r\n const maxLength = Math.max(lParts.length, rParts.length);\r\n\r\n for (let i = 0; i < maxLength; i++) {\r\n const l = lParts[i] || 0;\r\n const r = rParts[i] || 0;\r\n \r\n if (r > l) return true;\r\n if (r < l) return false;\r\n }\r\n \r\n return false; // 완전히 동일한 버전\r\n}","import { CimeErrorResponse } from '../types';\r\n\r\n/**\r\n * ci.me API 요청 중 발생하는 에러를 캡슐화한 커스텀 에러 클래스입니다.\r\n * HTTP 상태 코드와 API가 반환한 상세 메시지를 포함합니다.\r\n */\r\nexport class CimeAPIError extends Error {\r\n public readonly statusCode: number;\r\n\r\n /**\r\n * @param errorResponse - API 서버에서 반환한 에러 객체\r\n */\r\n constructor(errorResponse: CimeErrorResponse) {\r\n super(errorResponse.message);\r\n this.name = 'CimeAPIError';\r\n this.statusCode = errorResponse.statusCode;\r\n\r\n // TypeScript 환경에서 Custom Error 생성 시 prototype 체인을 수동으로 복구 (instanceof 정상 작동을 위함)\r\n Object.setPrototypeOf(this, CimeAPIError.prototype);\r\n }\r\n}","import axios, { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios';\r\nimport axiosRetry from 'axios-retry';\r\nimport { CimeAPIError } from '../errors/CimeAPIError';\r\nimport { CimeCommonResponse, CimeErrorResponse, CimeClientOptions } from '../types';\r\nimport { getVersion } from './version';\r\n\r\n/**\r\n * 인증 정보와 기본 설정이 포함된 Axios 클라이언트 인스턴스를 생성합니다.\r\n */\r\nexport function createHttpClient(options: CimeClientOptions): AxiosInstance {\r\n const client = axios.create({\r\n baseURL: 'https://ci.me/api/openapi',\r\n timeout: options.timeout || 10000,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'User-Agent': `CimeSDK/${getVersion()} (Node)`,\r\n },\r\n });\r\n\r\n client.interceptors.request.use((config: InternalAxiosRequestConfig) => {\r\n if (options.accessToken) {\r\n config.headers['Authorization'] = `Bearer ${options.accessToken}`;\r\n }\r\n if (options.clientId && options.clientSecret) {\r\n config.headers['Client-Id'] = options.clientId;\r\n config.headers['Client-Secret'] = options.clientSecret;\r\n }\r\n return config;\r\n });\r\n\r\n axiosRetry(client, {\r\n retries: options.retries ?? 3,\r\n retryDelay: axiosRetry.exponentialDelay,\r\n retryCondition: (error: AxiosError) => {\r\n return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 500;\r\n },\r\n });\r\n\r\n client.interceptors.response.use(\r\n (response: AxiosResponse<CimeCommonResponse>) => {\r\n return response.data.content as any;\r\n },\r\n (error: AxiosError<CimeErrorResponse>) => {\r\n if (error.response && error.response.data) {\r\n throw new CimeAPIError(error.response.data);\r\n }\r\n throw error;\r\n }\r\n );\r\n\r\n return client;\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeTokenResponse } from '../types/auth';\r\n\r\nexport class AuthAPI {\r\n constructor(\r\n private readonly http: AxiosInstance,\r\n private readonly config: { clientId?: string; clientSecret?: string }\r\n ) {}\r\n\r\n /**\r\n * Authorization Code를 사용하여 Access Token과 Refresh Token을 발급받습니다.\r\n * @param code Redirect URI로 전달받은 인가 코드\r\n */\r\n public async get(code: string): Promise<CimeTokenResponse> {\r\n this.validateCredentials();\r\n\r\n const { data } = await this.http.post<CimeTokenResponse>('/auth/v1/token', {\r\n grantType: 'authorization_code',\r\n clientId: this.config.clientId,\r\n clientSecret: this.config.clientSecret,\r\n code\r\n });\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Refresh Token을 사용하여 Access Token을 갱신합니다.\r\n * @param refreshToken 이전에 발급받은 리프레시 토큰\r\n */\r\n public async refresh(refreshToken: string): Promise<CimeTokenResponse> {\r\n this.validateCredentials();\r\n\r\n const { data } = await this.http.post<CimeTokenResponse>('/auth/v1/token', {\r\n grantType: 'refresh_token',\r\n clientId: this.config.clientId,\r\n clientSecret: this.config.clientSecret,\r\n refreshToken\r\n });\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * 내부 헬퍼: 토큰 발급 시 필요한 Client ID 및 Secret 유효성 검사 (Fail-fast)\r\n */\r\n private validateCredentials(): void {\r\n if (!this.config.clientId || !this.config.clientSecret) {\r\n throw new Error(\r\n '[Cime SDK] OAuth 토큰을 발급/갱신하려면 초기화 시 clientId와 clientSecret이 필요합니다.'\r\n );\r\n }\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeUser, CimeClientOptions } from '../types';\r\n\r\n/**\r\n * 사용자(User) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class UsersAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 현재 Access Token에 연결된 사용자의 채널 정보를 조회합니다.\r\n *\r\n * @requires Scope: `READ:USER`\r\n * @throws {CimeAPIError} Access Token이 없거나 만료되었을 때 (401), 또는 권한이 부족할 때 발생합니다.\r\n * @returns 사용자의 채널 상세 정보\r\n * * @example\r\n * ```typescript\r\n * const me = await client.users.get();\r\n * console.log(`안녕하세요, ${me.channelName}님!`);\r\n * ```\r\n */\r\n public async get(): Promise<CimeUser> {\r\n if (!this.options.scopes?.includes('READ:USER')) {\r\n throw new Error('[UsersAPI] \"READ:USER\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // 인터셉터에서 response.data.content를 바로 반환하므로 리턴 타입은 CimeUser가 됩니다.\r\n return this.httpClient.get<any, CimeUser>('/open/v1/users/me');\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeDataList,\r\n CimeChannelInfo,\r\n CimeFollower,\r\n CimeChannelFollowersParams,\r\n CimeSubscriber,\r\n CimeChannelSubscribersParams,\r\n CimeManager,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 채널(Channel) 관련 API를 담당하는 클래스입니다.\r\n * 채널 정보, 팔로워, 구독자, 관리자 목록 조회 기능을 제공합니다.\r\n */\r\nexport class ChannelsAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 채널 ID 목록으로 채널의 기본 정보를 조회합니다. (최대 20개)\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param channelIds - 조회할 채널 ID 문자열 또는 ID 문자열의 배열\r\n * @returns 채널 정보 목록\r\n * * @example\r\n * ```typescript\r\n * const { data } = await client.channels.getChannels(['12345', '67890']);\r\n * ```\r\n */\r\n public async getChannels(channelIds: string | string[]): Promise<CimeDataList<CimeChannelInfo>> {\r\n // 배열이 들어올 경우 쉼표로 구분된 문자열로 자동 변환하여 편의성을 높입니다.\r\n const parsedIds = Array.isArray(channelIds) ? channelIds.join(',') : channelIds;\r\n \r\n return this.httpClient.get<any, CimeDataList<CimeChannelInfo>>('/open/v1/channels', {\r\n params: { channelIds: parsedIds },\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 팔로워 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:CHANNEL`\r\n * @param params - 페이징 파라미터 (page, size)\r\n * @returns 팔로워 목록\r\n */\r\n public async getFollowers(params?: CimeChannelFollowersParams): Promise<CimeDataList<CimeFollower>> {\r\n if (!this.options.scopes?.includes('READ:CHANNEL')) {\r\n throw new Error('[ChannelsAPI] \"READ:CHANNEL\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeFollower>>('/open/v1/channels/followers', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 구독자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:SUBSCRIPTION`\r\n * @param params - 페이징 및 정렬 파라미터 (page, size, sort)\r\n * @returns 구독자 목록\r\n */\r\n public async getSubscribers(params?: CimeChannelSubscribersParams): Promise<CimeDataList<CimeSubscriber>> {\r\n if (!this.options.scopes?.includes('READ:SUBSCRIPTION')) {\r\n throw new Error('[ChannelsAPI] \"READ:SUBSCRIPTION\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeSubscriber>>('/open/v1/channels/subscribers', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 관리자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:CHANNEL`\r\n * @returns 관리자 목록\r\n */\r\n public async getManagers(): Promise<CimeDataList<CimeManager>> {\r\n if (!this.options.scopes?.includes('READ:CHANNEL')) {\r\n throw new Error('[ChannelsAPI] \"READ:CHANNEL\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeDataList<CimeManager>>('/open/v1/channels/streaming-roles');\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeCursorList,\r\n CimeLive,\r\n CimeLivesParams,\r\n CimeLiveSetting,\r\n CimeUpdateLiveSettingParams,\r\n CimeStreamKey,\r\n CimeLiveStatus,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 라이브(Live) 및 스트리밍 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class LiveAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 현재 진행 중인 라이브 방송 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param params - 커서 기반 페이징 파라미터 (size, next)\r\n * @returns 라이브 목록과 다음 페이지 커서 정보\r\n */\r\n public async getLives(params?: CimeLivesParams): Promise<CimeCursorList<CimeLive>> {\r\n return this.httpClient.get<any, CimeCursorList<CimeLive>>('/open/v1/lives', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 라이브 설정을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_STREAM_SETTINGS`\r\n * @returns 라이브 설정 정보\r\n */\r\n public async getSettings(): Promise<CimeLiveSetting> {\r\n if (!this.options.scopes?.includes('READ:LIVE_STREAM_SETTINGS')) {\r\n throw new Error('[LiveAPI] \"READ:LIVE_STREAM_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeLiveSetting>('/open/v1/lives/setting');\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 라이브 설정을 변경합니다. (전달된 필드만 업데이트)\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_STREAM_SETTINGS`\r\n * @param params - 변경할 라이브 설정 데이터\r\n */\r\n public async updateSettings(params: CimeUpdateLiveSettingParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_STREAM_SETTINGS')) {\r\n throw new Error('[LiveAPI] \"WRITE:LIVE_STREAM_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.patch('/open/v1/lives/setting', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 스트림 키(Stream Key)를 조회합니다.\r\n * OBS 등 외부 방송 도구 연동 시 사용됩니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_STREAM_KEY`\r\n * @returns 스트림 키\r\n */\r\n public async getStreamKey(): Promise<CimeStreamKey> {\r\n if (!this.options.scopes?.includes('READ:LIVE_STREAM_KEY')) {\r\n throw new Error('[LiveAPI] \"READ:LIVE_STREAM_KEY\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeStreamKey>('/open/v1/streams/key');\r\n }\r\n\r\n /**\r\n * 특정 채널의 라이브 방송 여부와 상태를 확인합니다.\r\n * 이 API는 인증 없이 호출할 수 있는 완전 공개 API입니다.\r\n *\r\n * @requires Auth: 불필요\r\n * @param channelId - 상태를 조회할 채널의 ID\r\n * @returns 라이브 상태 정보\r\n */\r\n public async getLiveStatus(channelId: string): Promise<CimeLiveStatus> {\r\n // 주의: 이 엔드포인트는 /open/v1/ 접두사 없이 /v1/ 으로 시작합니다.\r\n return this.httpClient.get<any, CimeLiveStatus>(`/v1/${channelId}/live-status`);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeChatSettings,\r\n CimeUpdateChatSettingsParams,\r\n CimeSendChatMessageParams,\r\n CimeSendChatMessageResponse,\r\n CimeRegisterChatNoticeParams,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 라이브 채팅(Chat) 설정 및 메시지 전송 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class ChatAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 인증된 사용자 채널의 채팅 설정을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:LIVE_CHAT_SETTINGS`\r\n * @returns 채팅 설정 정보\r\n */\r\n public async getSettings(): Promise<CimeChatSettings> {\r\n if (!this.options.scopes?.includes('READ:LIVE_CHAT_SETTINGS')) {\r\n throw new Error('[ChatAPI] \"READ:LIVE_CHAT_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeChatSettings>('/open/v1/chats/settings');\r\n }\r\n\r\n /**\r\n * 인증된 사용자 채널의 채팅 설정을 변경합니다. (전달된 필드만 업데이트)\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT_SETTINGS`\r\n * @param params - 변경할 채팅 설정 데이터\r\n */\r\n public async updateSettings(params: CimeUpdateChatSettingsParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT_SETTINGS')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT_SETTINGS\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.put('/open/v1/chats/settings', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널 라이브 채팅에 메시지를 전송합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT`\r\n * @param params - 전송할 메시지 정보 및 발신자 타입\r\n * @returns 전송된 메시지 ID\r\n */\r\n public async sendMessage(params: CimeSendChatMessageParams): Promise<CimeSendChatMessageResponse> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.post<any, CimeSendChatMessageResponse>('/open/v1/chats/send', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널 라이브 채팅에 공지사항을 등록합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:LIVE_CHAT_NOTICE`\r\n * @param params - 등록할 공지 메시지 내용 또는 기존 메시지 ID\r\n * @throws {Error} 파라미터가 모두 누락된 경우 서버 요청 전 사전 차단합니다.\r\n */\r\n public async registerNotice(params: CimeRegisterChatNoticeParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:LIVE_CHAT_NOTICE')) {\r\n throw new Error('[ChatAPI] \"WRITE:LIVE_CHAT_NOTICE\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // Fail-fast 로직: 서버로 보내기 전 SDK 단에서 미리 파라미터 유효성 검사\r\n if (!params.message && !params.messageId) {\r\n throw new Error('[CimeClient.ChatAPI] registerNotice requires either \"message\" or \"messageId\".');\r\n }\r\n\r\n await this.httpClient.post('/open/v1/chats/notice', params);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeDataList, CimeCategory, CimeSearchCategoriesParams } from '../types';\r\n\r\n/**\r\n * 카테고리(Category) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class CategoriesAPI {\r\n constructor(private readonly httpClient: AxiosInstance) {}\r\n\r\n /**\r\n * 라이브 설정 등에 사용할 카테고리를 키워드로 검색합니다.\r\n *\r\n * @requires Auth: `Client ID / Secret` (공개 API)\r\n * @param params - 검색 키워드 및 페이지 크기 파라미터\r\n * @returns 검색된 카테고리 목록\r\n */\r\n public async searchCategories(params?: CimeSearchCategoriesParams): Promise<CimeDataList<CimeCategory>> {\r\n return this.httpClient.get<any, CimeDataList<CimeCategory>>('/open/v1/categories/search', {\r\n params,\r\n });\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport {\r\n CimeCursorList,\r\n CimeRestrictUserParams,\r\n CimeGetRestrictedUsersParams,\r\n CimeRestrictedUser,\r\n CimeClientOptions,\r\n} from '../types';\r\n\r\n/**\r\n * 사용자 차단 및 추방(Restrict) 관련 API를 담당하는 클래스입니다.\r\n */\r\nexport class RestrictAPI {\r\n constructor(private readonly httpClient: AxiosInstance, private readonly options: CimeClientOptions) {}\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 특정 사용자를 추방합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:USER_BLOCK`\r\n * @param params - 추방할 대상 채널 ID\r\n */\r\n public async restrictUser(params: CimeRestrictUserParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"WRITE:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n await this.httpClient.post('/open/v1/restrict-channels', params);\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 추방된 사용자 목록을 조회합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `READ:USER_BLOCK`\r\n * @param params - 커서 기반 페이징 파라미터 (size, next)\r\n * @returns 추방된 사용자 목록\r\n */\r\n public async getRestrictedUsers(\r\n params?: CimeGetRestrictedUsersParams\r\n ): Promise<CimeCursorList<CimeRestrictedUser>> {\r\n if (!this.options.scopes?.includes('READ:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"READ:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n return this.httpClient.get<any, CimeCursorList<CimeRestrictedUser>>('/open/v1/restrict-channels', {\r\n params,\r\n });\r\n }\r\n\r\n /**\r\n * 인증된 사용자의 채널에서 특정 사용자의 추방을 해제합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @requires Scope: `WRITE:USER_BLOCK`\r\n * @param params - 추방 해제할 대상 채널 ID\r\n */\r\n public async unrestrictUser(params: CimeRestrictUserParams): Promise<void> {\r\n if (!this.options.scopes?.includes('WRITE:USER_BLOCK')) {\r\n throw new Error('[RestrictAPI] \"WRITE:USER_BLOCK\" 권한이 필요합니다. OAuth 인증 시 해당 권한을 포함시켜 주세요.');\r\n }\r\n // Axios에서 DELETE 요청에 Request Body를 담으려면 두 번째 인자인 config의 data 필드에 넣어야 합니다.\r\n await this.httpClient.delete('/open/v1/restrict-channels', {\r\n data: params,\r\n });\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeSessionResponse, CimeSessionType, CimeEventName } from '../types';\r\n\r\n/**\r\n * 세션(Session) 및 이벤트 구독 제어를 담당하는 클래스입니다.\r\n */\r\nexport class SessionsAPI {\r\n constructor(private readonly httpClient: AxiosInstance) {}\r\n\r\n /**\r\n * WebSocket 연결을 위한 새로운 세션을 생성합니다.\r\n *\r\n * @param type - 세션 유형 ('USER' 또는 'CLIENT')\r\n * @returns WebSocket URL을 포함한 세션 정보\r\n */\r\n public async createSession(type: CimeSessionType): Promise<CimeSessionResponse> {\r\n const endpoint = type === 'USER' ? '/open/v1/sessions/auth' : '/open/v1/sessions/auth/client';\r\n return this.httpClient.get<any, CimeSessionResponse>(endpoint);\r\n }\r\n\r\n /**\r\n * 특정 세션에 이벤트를 구독합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @param event - 구독할 이벤트 이름 (chat, donation, subscription)\r\n * @param sessionKey - 세션 키\r\n */\r\n public async subscribeEvent(event: CimeEventName, sessionKey: string): Promise<void> {\r\n await this.httpClient.post(`/open/v1/sessions/events/subscribe/${event}`, null, {\r\n params: { sessionKey },\r\n });\r\n }\r\n\r\n /**\r\n * 특정 세션에서 이벤트 구독을 해제합니다.\r\n *\r\n * @requires Auth: `Access Token`\r\n * @param event - 구독 해제할 이벤트 이름\r\n * @param sessionKey - 세션 키\r\n */\r\n public async unsubscribeEvent(event: CimeEventName, sessionKey: string): Promise<void> {\r\n await this.httpClient.post(`/open/v1/sessions/events/unsubscribe/${event}`, null, {\r\n params: { sessionKey },\r\n });\r\n }\r\n}","import WebSocket from 'ws';\r\nimport { EventEmitter } from 'events';\r\nimport { SessionsAPI } from '../api/sessions';\r\nimport { CimeEventClientOptions, CimeEventPayload } from '../types';\r\nimport { CimeChatEventData } from '../types/chat';\r\nimport { CimeDonationEventData } from '../types/donation';\r\nimport { CimeSubscriptionEventData } from '../types/subscription';\r\n\r\nexport type CimeLiveEventName = 'CHAT' | 'DONATION' | 'SUBSCRIPTION';\r\n\r\nexport declare interface CimeEventClient {\r\n on(event: 'CHAT', listener: (data: CimeChatEventData) => void): this;\r\n on(event: 'DONATION', listener: (data: CimeDonationEventData) => void): this;\r\n on(event: 'SUBSCRIPTION', listener: (data: CimeSubscriptionEventData) => void): this;\r\n \r\n on(event: 'connected', listener: () => void): this;\r\n on(event: 'disconnected', listener: () => void): this;\r\n on(event: 'error', listener: (error: Error) => void): this;\r\n on(event: 'reconnecting', listener: () => void): this;\r\n on(event: string | symbol, listener: (...args: any[]) => void): this;\r\n\r\n emit(event: 'CHAT', data: CimeChatEventData): boolean;\r\n emit(event: 'DONATION', data: CimeDonationEventData): boolean;\r\n emit(event: 'SUBSCRIPTION', data: CimeSubscriptionEventData): boolean;\r\n \r\n emit(event: 'connected'): boolean;\r\n emit(event: 'disconnected'): boolean;\r\n emit(event: 'error', error: Error): boolean;\r\n emit(event: 'reconnecting'): boolean;\r\n emit(event: string | symbol, ...args: any[]): boolean;\r\n}\r\n\r\n/**\r\n * ci.me API의 실시간 이벤트를 수신하기 위한 WebSocket 클라이언트입니다.\r\n */\r\nexport class CimeEventClient extends EventEmitter {\r\n private ws: WebSocket | null = null;\r\n private sessionKey: string | null = null;\r\n private pingTimer: NodeJS.Timeout | null = null;\r\n private reconnectTimer: NodeJS.Timeout | null = null;\r\n \r\n private isConnecting = false;\r\n private isIntentionalClose = false;\r\n \r\n private readonly activeSubscriptions = new Set<CimeLiveEventName>();\r\n\r\n constructor(\r\n private readonly sessionsApi: SessionsAPI,\r\n private readonly options: CimeEventClientOptions\r\n ) {\r\n super();\r\n }\r\n\r\n public async connect(): Promise<void> {\r\n if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) return;\r\n this.isConnecting = true;\r\n this.isIntentionalClose = false;\r\n\r\n try {\r\n const { url } = await this.sessionsApi.createSession(this.options.type);\r\n \r\n const parsedUrl = new URL(url);\r\n this.sessionKey = parsedUrl.searchParams.get('sessionKey');\r\n \r\n if (!this.sessionKey) {\r\n throw new Error('[CimeEventClient] Failed to extract sessionKey from URL.');\r\n }\r\n\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.on('open', async () => {\r\n this.isConnecting = false;\r\n this.startPing();\r\n this.emit('connected');\r\n\r\n for (const event of this.activeSubscriptions) {\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n await this.sessionsApi.subscribeEvent(apiEventName, this.sessionKey!).catch(err => {\r\n this.emit('error', new Error(`Failed to resubscribe ${event}: ${err.message}`));\r\n });\r\n }\r\n });\r\n\r\n this.ws.on('message', (data: WebSocket.RawData) => {\r\n this.handleMessage(data.toString());\r\n });\r\n\r\n this.ws.on('close', () => {\r\n this.cleanup();\r\n this.emit('disconnected');\r\n this.handleReconnect();\r\n });\r\n\r\n this.ws.on('error', (error) => {\r\n this.emit('error', error);\r\n });\r\n\r\n } catch (error) {\r\n this.isConnecting = false;\r\n this.emit('error', error as Error);\r\n this.handleReconnect(); \r\n }\r\n }\r\n\r\n /**\r\n * 실시간 이벤트를 구독합니다.\r\n * @param event - 'CHAT' | 'DONATION' | 'SUBSCRIPTION'\r\n */\r\n public async subscribe(event: CimeLiveEventName): Promise<void> {\r\n if (this.activeSubscriptions.size >= 30) {\r\n throw new Error('[CimeEventClient] Exceeded maximum 30 subscriptions per session.');\r\n }\r\n\r\n this.activeSubscriptions.add(event);\r\n \r\n // API 통신 시에는 소문자로 변환하여 전송합니다.\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n\r\n if (this.sessionKey && this.ws?.readyState === WebSocket.OPEN) {\r\n await this.sessionsApi.subscribeEvent(apiEventName, this.sessionKey);\r\n }\r\n }\r\n\r\n /**\r\n * 실시간 이벤트 구독을 해제합니다.\r\n * @param event - 'CHAT' | 'DONATION' | 'SUBSCRIPTION'\r\n */\r\n public async unsubscribe(event: CimeLiveEventName): Promise<void> {\r\n this.activeSubscriptions.delete(event);\r\n\r\n const apiEventName = event.toLowerCase() as 'chat' | 'donation' | 'subscription';\r\n\r\n if (this.sessionKey && this.ws?.readyState === WebSocket.OPEN) {\r\n await this.sessionsApi.unsubscribeEvent(apiEventName, this.sessionKey);\r\n }\r\n }\r\n\r\n public disconnect(): void {\r\n this.isIntentionalClose = true;\r\n this.activeSubscriptions.clear();\r\n this.cleanup();\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n }\r\n\r\n private handleMessage(message: string): void {\r\n try {\r\n const payload = JSON.parse(message);\r\n \r\n if (payload.action === 'PONG') return;\r\n\r\n if (payload.event && payload.data) {\r\n const typedPayload = payload as CimeEventPayload;\r\n this.emit(typedPayload.event as any, typedPayload.data);\r\n }\r\n } catch (error) {\r\n this.emit('error', new Error(`[CimeEventClient] Failed to parse message: ${message}`));\r\n }\r\n }\r\n\r\n private startPing(): void {\r\n const interval = this.options.pingInterval || 60000;\r\n this.pingTimer = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify({ type: 'PING' }));\r\n }\r\n }, interval);\r\n }\r\n\r\n private cleanup(): void {\r\n if (this.pingTimer) {\r\n clearInterval(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n this.isConnecting = false;\r\n }\r\n\r\n private async handleReconnect(): Promise<void> {\r\n if (this.isIntentionalClose) return;\r\n\r\n if (this.options.onTokenRefresh) {\r\n try {\r\n await this.options.onTokenRefresh();\r\n } catch (err) {\r\n this.emit('error', new Error('[CimeEventClient] Token refresh failed during reconnect.'));\r\n }\r\n }\r\n\r\n this.reconnectTimer = setTimeout(() => {\r\n this.emit('reconnecting');\r\n this.connect();\r\n }, 5000);\r\n }\r\n}","import { AxiosInstance } from 'axios';\r\nimport { CimeClientOptions, CimeTokenResponse, CimeEventClientOptions } from './types';\r\nimport { createHttpClient } from './utils/httpClient';\r\nimport { AuthAPI } from './api/auth';\r\nimport { UsersAPI } from './api/users';\r\nimport { ChannelsAPI } from './api/channels';\r\nimport { LiveAPI } from './api/live';\r\nimport { ChatAPI } from './api/chat';\r\nimport { CategoriesAPI } from './api/categories';\r\nimport { RestrictAPI } from './api/restrict';\r\nimport { SessionsAPI } from './api/sessions';\r\nimport { CimeEventClient } from './ws/CimeEventClient';\r\n\r\n/**\r\n * ci.me API를 사용하기 위한 메인 클라이언트 클래스입니다.\r\n */\r\nexport class CimeClient {\r\n private readonly httpClient: AxiosInstance;\r\n private options: CimeClientOptions;\r\n\r\n public readonly auth: AuthAPI;\r\n public readonly users: UsersAPI;\r\n public readonly channels: ChannelsAPI;\r\n public readonly live: LiveAPI;\r\n public readonly chat: ChatAPI;\r\n public readonly categories: CategoriesAPI;\r\n public readonly restrict: RestrictAPI;\r\n public readonly sessions: SessionsAPI;\r\n\r\n constructor(options: CimeClientOptions) {\r\n // [버그 수정됨] accessToken이 없고, (clientId 또는 clientSecret이 없을 때) 에러를 발생시킵니다.\r\n if (!options.accessToken && (!options.clientId || !options.clientSecret)) {\r\n throw new Error('[CimeClient] Authentication credentials (accessToken OR clientId/Secret) are required.');\r\n }\r\n\r\n this.options = { ...options };\r\n this.httpClient = createHttpClient(this.options);\r\n\r\n this.auth = new AuthAPI(this.httpClient, { clientId: this.options.clientId, clientSecret: this.options.clientSecret });\r\n this.users = new UsersAPI(this.httpClient, this.options);\r\n this.channels = new ChannelsAPI(this.httpClient, this.options);\r\n this.live = new LiveAPI(this.httpClient, this.options);\r\n this.chat = new ChatAPI(this.httpClient, this.options);\r\n this.categories = new CategoriesAPI(this.httpClient);\r\n this.restrict = new RestrictAPI(this.httpClient, this.options);\r\n this.sessions = new SessionsAPI(this.httpClient);\r\n }\r\n\r\n public setAccessToken(token: string): void {\r\n this.options.accessToken = token;\r\n // httpClient 내부의 options 참조는 객체 참조이므로 속성만 바꿔주면 다음 요청부터 자동으로 반영됩니다.\r\n }\r\n\r\n /**\r\n * 실시간 이벤트를 수신하기 위한 WebSocket 클라이언트를 생성합니다.\r\n */\r\n public createEventClient(options: CimeEventClientOptions): CimeEventClient {\r\n if (options.refreshToken && !options.onTokenRefresh) {\r\n options.onTokenRefresh = async () => {\r\n try {\r\n const tokenInfo = await this.auth.refresh(options.refreshToken!);\r\n this.setAccessToken(tokenInfo.accessToken);\r\n options.refreshToken = tokenInfo.refreshToken;\r\n } catch (error) {\r\n throw new Error('자동 토큰 갱신에 실패했습니다.');\r\n }\r\n };\r\n }\r\n return new CimeEventClient(this.sessions, options);\r\n }\r\n\r\n /** * OAuth 인증 플로우를 통해 Access Token을 발급받고 클라이언트에 설정합니다.\r\n * @param code Redirect URI로 전달받은 인가 코드\r\n * @throws 인증 정보(clientId/Secret)가 없으면 에러를 반환합니다.\r\n */\r\n public async authorize(code: string): Promise<CimeTokenResponse> {\r\n if (!this.options.clientId || !this.options.clientSecret) {\r\n throw new Error('[CimeClient] OAuth authentication requires clientId and clientSecret to be set in options.');\r\n }\r\n\r\n const tokenResponse = await this.auth.get(code);\r\n this.setAccessToken(tokenResponse.accessToken);\r\n return tokenResponse;\r\n }\r\n}","import { CimeChatEventData } from '../types/chat';\r\n\r\n/**\r\n * 채팅 메시지 내의 이모티콘 토큰을 <img> 태그로 변환합니다.\r\n * 따로 UI를 만드실 계획이 아니시라면, 별 쓸모는 없습니다.\r\n * @param data 채팅 이벤트 데이터 (content, emojis)\r\n * @param className <img> 태그에 부여할 CSS 클래스명 (기본값: 'cime-emoji')\r\n * @returns 변환된 HTML 문자열\r\n */\r\nexport function renderChatEmojisToHTML(\r\n data: Pick<CimeChatEventData, 'content' | 'emojis'>,\r\n className: string = 'cime-emoji'\r\n): string {\r\n if (!data.emojis || Object.keys(data.emojis).length === 0) {\r\n return data.content;\r\n }\r\n\r\n let htmlMessage = data.content;\r\n\r\n for (const [token, imageUrl] of Object.entries(data.emojis)) {\r\n // 1. 토큰 내의 정규식 특수문자 안전하게 이스케이프 처리\r\n const escapedToken = token.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n const regex = new RegExp(escapedToken, 'g');\r\n\r\n // 2. replace의 두 번째 인자로 문자열 대신 '콜백 함수'를 사용하여\r\n // '$$' 기호가 단일 '$'로 치환되는 JavaScript 고유의 버그를 방지합니다.\r\n htmlMessage = htmlMessage.replace(regex, () => {\r\n return `<img src=\"${imageUrl}\" alt=\"${token}\" class=\"${className}\" />`;\r\n });\r\n }\r\n\r\n return htmlMessage;\r\n}","import { checkVersion } from './utils/version';\r\ncheckVersion();\r\n\r\nexport { CimeClient } from './client';\r\n\r\nexport { CimeAPIError } from './errors/CimeAPIError';\r\n\r\nexport { CimeEventClient, CimeLiveEventName } from './ws/CimeEventClient';\r\n\r\nexport * from './types';\r\n\r\nexport * from './utils/chatUtils';\r\nexport { getVersion } from './utils/version';"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cime-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A structural and object-oriented TypeScript SDK for ci.me API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -21,10 +21,17 @@
21
21
  "test": "vitest",
22
22
  "typecheck": "tsc --noEmit"
23
23
  },
24
- "keywords": ["cime", "sdk", "typescript"],
24
+ "keywords": [
25
+ "cime",
26
+ "sdk",
27
+ "typescript"
28
+ ],
25
29
  "author": "whitespaca",
26
30
  "license": "MIT",
27
- "repository": {"type": "git", "url": "https://github.com/whitespaca/cime-sdk" },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/whitespaca/cime-sdk"
34
+ },
28
35
  "type": "commonjs",
29
36
  "dependencies": {
30
37
  "axios": "^1.15.0",