@nowsoft-lab/chear-widget-react 0.0.0-stage → 1.0.1
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 +183 -2
- package/dist/index.d.ts +27 -0
- package/dist/index.js +66 -0
- package/dist/loader.d.ts +13 -0
- package/dist/loader.js +32 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.js +4 -0
- package/package.json +52 -4
package/README.md
CHANGED
|
@@ -1,3 +1,184 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @nowsoft-lab/chear-widget-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@nowsoft-lab/chear-widget-react)
|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
치어(CHEAR) 라이브 방송의 **플레이어**와 **채팅**을 리액트 앱에 컴포넌트로 넣습니다.
|
|
7
|
+
채널 아이디 하나만 넘기면 스튜디오 › 위젯과 **같은 화면 · 같은 동작**이 나오고, 위젯이 개선되면 이 패키지를 다시 설치하지 않아도 같이 바뀝니다.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { ChearPlayer, ChearChat } from "@nowsoft-lab/chear-widget-react";
|
|
11
|
+
|
|
12
|
+
export default function Live() {
|
|
13
|
+
return (
|
|
14
|
+
<div style={{ display: "flex", gap: 16 }}>
|
|
15
|
+
<ChearPlayer channel="streamer01" style={{ flex: 1 }} />
|
|
16
|
+
<ChearChat channel="streamer01" style={{ width: 360, height: 600 }} />
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- API 키 · 백엔드 연동 없이 바로 씁니다.
|
|
23
|
+
- 방송 중이면 재생, 아니면 채널 프로필과 "방송 준비 중"을 보여 줍니다. 방송이 시작되면 저절로 재생으로 바뀝니다.
|
|
24
|
+
- 채팅은 읽기만이 아니라 **실제로 채팅**합니다 — 로그인 · 가입 · 이모티콘 · 신고 · 팔로우가 위젯 안에서 됩니다.
|
|
25
|
+
- 위젯은 Shadow DOM 안에 그려져 내 사이트 스타일과 서로 섞이지 않습니다.
|
|
26
|
+
|
|
27
|
+
## 설치
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npm i @nowsoft-lab/chear-widget-react
|
|
31
|
+
# 또는
|
|
32
|
+
pnpm add @nowsoft-lab/chear-widget-react
|
|
33
|
+
yarn add @nowsoft-lab/chear-widget-react
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- React 18 이상(18 · 19).
|
|
37
|
+
- ES 모듈만 제공합니다(Vite · Next.js · webpack 5 · Rspack 등 요즘 번들러는 그대로 됩니다).
|
|
38
|
+
- 타입(TypeScript) 포함.
|
|
39
|
+
|
|
40
|
+
## 컴포넌트
|
|
41
|
+
|
|
42
|
+
### `<ChearPlayer>` — 방송 플레이어
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
<ChearPlayer channel="streamer01" />
|
|
46
|
+
<ChearPlayer channel="streamer01" chat /> {/* 오른쪽에 채팅 같이 */}
|
|
47
|
+
<ChearPlayer channel="streamer01" muted={false} autoplay={false} />
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| prop | 타입 | 기본 | 설명 |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| `channel` | `string` | **필수** | 채널 아이디(스튜디오에 보이는 @아이디) |
|
|
53
|
+
| `autoplay` | `boolean` | `true` | 자동 재생. 브라우저 정책상 소리 끔과 함께일 때만 확실합니다 |
|
|
54
|
+
| `muted` | `boolean` | `true` | 소리 끔으로 시작. 화면의 "소리 켜기"로 켤 수 있습니다 |
|
|
55
|
+
| `controls` | `boolean` | `true` | 재생 컨트롤 표시 |
|
|
56
|
+
| `chat` | `boolean` | `false` | 플레이어 오른쪽에 채팅을 같이(좁은 세로 화면은 아래). 컨트롤의 채팅 단추로 접고 펼칩니다 |
|
|
57
|
+
| `stats` | `boolean` | `true` | 왼쪽 위 LIVE · 시청 중 표시 |
|
|
58
|
+
|
|
59
|
+
**크기** — 기본은 부모 폭 100% · 16:9 입니다. 폭만 정하면 높이는 따라옵니다.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<ChearPlayer channel="streamer01" style={{ width: 640 }} /> {/* 640 × 360 */}
|
|
63
|
+
<ChearPlayer channel="streamer01" className="my-player" /> {/* CSS 로 */}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `<ChearChat>` — 채팅
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
<ChearChat channel="streamer01" style={{ width: 360, height: 600 }} />
|
|
70
|
+
<ChearChat channel="streamer01" theme="light" />
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| prop | 타입 | 기본 | 설명 |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| `channel` | `string` | **필수** | 채널 아이디 |
|
|
76
|
+
| `theme` | `"dark" \| "light"` | `"dark"` | 다크 · 라이트 |
|
|
77
|
+
|
|
78
|
+
**크기** — 기본은 폭 100% · 부모 높이(부모에 높이가 없으면 최소 480px). 높이를 꼭 정해 주세요.
|
|
79
|
+
|
|
80
|
+
### 공통 prop
|
|
81
|
+
|
|
82
|
+
| prop | 타입 | 설명 |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `ssoToken` | `string` | 간편 로그인(SSO) 토큰 — 내 사이트 회원을 바로 채팅에 로그인시킵니다. [아래](#간편-로그인sso) |
|
|
85
|
+
| `origin` | `string` | 위젯 출처. 기본 `https://player.chear.live`. 보통은 안 넣습니다 |
|
|
86
|
+
| `className` · `style` | | 위젯 바깥 div 에 그대로 |
|
|
87
|
+
| `onError` | `(error) => void` | 위젯을 불러오지 못했을 때(네트워크 · 사이트 보안 정책) |
|
|
88
|
+
|
|
89
|
+
### `<ChearProvider>` — 위젯 출처 한 번에
|
|
90
|
+
|
|
91
|
+
개발서버나 다른 플랫폼 위젯을 쓸 때만 필요합니다.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { ChearProvider, ChearPlayer, ChearChat } from "@nowsoft-lab/chear-widget-react";
|
|
95
|
+
|
|
96
|
+
<ChearProvider origin="https://dev.chear.live">
|
|
97
|
+
<ChearPlayer channel="streamer01" />
|
|
98
|
+
<ChearChat channel="streamer01" />
|
|
99
|
+
</ChearProvider>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Next.js
|
|
103
|
+
|
|
104
|
+
App Router 에서 그대로 씁니다. 패키지에 `"use client"` 가 들어 있어 서버 컴포넌트에서 바로 import 해도 됩니다 — 서버에서는 빈 div 만 그리고, 브라우저에서 위젯이 뜹니다.
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// app/live/page.tsx
|
|
108
|
+
import { ChearPlayer } from "@nowsoft-lab/chear-widget-react";
|
|
109
|
+
|
|
110
|
+
export default function Page() {
|
|
111
|
+
return <ChearPlayer channel="streamer01" />;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 간편 로그인(SSO)
|
|
116
|
+
|
|
117
|
+
내 사이트에 로그인한 회원을 치어 계정 없이 바로 채팅에 들어오게 합니다(치어에서 파트너 SSO 를 켠 경우).
|
|
118
|
+
**내 서버**에서 SSO 비밀값으로 짧은 토큰(JWT HS256, 5분 이하)을 만들어 컴포넌트에 넘깁니다 — 비밀값은 브라우저에 두지 마세요.
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
const { token } = await fetch("/my-api/chear-sso").then((r) => r.json()); // 내 서버가 만든 토큰
|
|
122
|
+
<ChearChat channel="streamer01" ssoToken={token} />
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- 토큰 형식(claims) · 서버 예제(Node · PHP · Java) · 오류 코드: 스튜디오 › 위젯 › 채팅 › "간편 로그인 안내" 또는 [개발자 문서](https://www.chear.live/developers/api).
|
|
126
|
+
- 토큰은 한 번만 쓸 수 있습니다. 새 토큰을 넘기면 위젯이 다시 로그인합니다.
|
|
127
|
+
|
|
128
|
+
## 내 사이트 설정
|
|
129
|
+
|
|
130
|
+
### 허용 도메인
|
|
131
|
+
|
|
132
|
+
채널 설정에 "허용 도메인"이 있으면 **그 사이트에서만 로그인 · 채팅**할 수 있습니다(아니면 로그인 때 `EMB-005`). 보기 · 재생은 막지 않습니다.
|
|
133
|
+
채널 설정에서 "퍼가기 허용"을 끄면 어디서든 안내만 나옵니다.
|
|
134
|
+
|
|
135
|
+
### CSP(Content-Security-Policy)
|
|
136
|
+
|
|
137
|
+
사이트에 CSP 를 쓰고 있다면 아래를 더해 주세요.
|
|
138
|
+
|
|
139
|
+
| 지시어 | 넣을 주소 |
|
|
140
|
+
|---|---|
|
|
141
|
+
| `script-src` | `https://player.chear.live` |
|
|
142
|
+
| `connect-src` | `https://player.chear.live` `https://*.edge.naverncp.com` `https://*.firebasedatabase.app` `wss://*.firebasedatabase.app` `https://firestore.googleapis.com` `https://identitytoolkit.googleapis.com` `https://securetoken.googleapis.com` |
|
|
143
|
+
| `media-src` | `blob:` `https://*.edge.naverncp.com` |
|
|
144
|
+
| `img-src` | `https://*.edge.naverncp.com` `data:` |
|
|
145
|
+
| `style-src` | `https://cdn.jsdelivr.net` `'unsafe-inline'` |
|
|
146
|
+
| `font-src` | `https://cdn.jsdelivr.net` |
|
|
147
|
+
|
|
148
|
+
`ChearProvider` 로 다른 출처를 쓰면 `player.chear.live` 자리에 그 출처를 넣습니다.
|
|
149
|
+
|
|
150
|
+
### 브라우저 저장소
|
|
151
|
+
|
|
152
|
+
채팅 로그인 정보는 이 사이트의 `localStorage` 에 `chear.widget:` 로 시작하는 키로 둡니다. 채팅 · 신고 · 팔로우만 되는 짧은 토큰이고, 결제 · 마이페이지 같은 권한은 없습니다.
|
|
153
|
+
사이트 스크립트와 완전히 떼어 두어야 한다면 스튜디오 › 위젯의 **iframe 위젯**을 쓰세요.
|
|
154
|
+
|
|
155
|
+
## 동작 방식
|
|
156
|
+
|
|
157
|
+
이 패키지는 얇은 껍데기입니다. 화면은 위젯 출처의 런타임(`https://player.chear.live/sdk/v1/runtime.js`)이 그립니다.
|
|
158
|
+
|
|
159
|
+
1. 컴포넌트가 처음 그려질 때 런타임을 한 번 받습니다(브라우저 캐시 · 여러 컴포넌트가 함께 씀).
|
|
160
|
+
2. 컴포넌트의 div 에 Shadow DOM 을 열고 그 안에 위젯을 그립니다. 모달 · 로그인 창 · 전체 화면도 위젯 틀 안에서만 동작합니다.
|
|
161
|
+
3. prop 이 바뀌면 다시 받지 않고 그 자리에서 바뀝니다.
|
|
162
|
+
|
|
163
|
+
그래서 화면 · 기능 개선은 런타임 배포만으로 모든 사이트에 반영됩니다. 이 패키지의 판은 prop 이 바뀔 때만 올라갑니다.
|
|
164
|
+
|
|
165
|
+
## 판 정책
|
|
166
|
+
|
|
167
|
+
| 판 | 런타임 | |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| 1.x | `/sdk/v1/` | 지금. prop 추가는 1.x 안에서(기존 코드 그대로 동작) |
|
|
170
|
+
| 2.x | `/sdk/v2/` | prop 을 바꾸거나 빼는 큰 변경일 때만. 1.x 는 한동안 함께 유지 |
|
|
171
|
+
|
|
172
|
+
## 문제 해결
|
|
173
|
+
|
|
174
|
+
| 증상 | 확인할 것 |
|
|
175
|
+
|---|---|
|
|
176
|
+
| 아무것도 안 보임 | `onError` 로 오류 확인. 사이트 CSP 의 `script-src` · 광고 차단 확장 |
|
|
177
|
+
| "이 채널은 퍼가기를 허용하지 않아요" | 채널 설정의 퍼가기 허용 |
|
|
178
|
+
| 로그인하면 `EMB-005` | 채널 허용 도메인에 내 사이트 도메인 추가 |
|
|
179
|
+
| 채팅 높이가 0 · 너무 작음 | `<ChearChat>` 또는 부모에 높이 지정 |
|
|
180
|
+
| 소리가 안 나옴 | 자동 재생은 소리 끔으로 시작합니다. 화면의 "소리 켜기" 또는 `muted={false}`(브라우저가 막으면 소리 끔으로 재생) |
|
|
181
|
+
|
|
182
|
+
## 라이선스
|
|
183
|
+
|
|
184
|
+
UNLICENSED — 치어 위젯을 넣는 용도로만 씁니다.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
import type { ChatOptions, PlayerOptions } from "./types";
|
|
3
|
+
export { DEFAULT_ORIGIN, loadRuntime, runtimeUrl } from "./loader";
|
|
4
|
+
export type { ChatOptions, PlayerOptions } from "./types";
|
|
5
|
+
/** 위젯 출처를 바꿀 때만(개발서버 · 다른 플랫폼). 운영 치어는 필요 없음 */
|
|
6
|
+
export declare function ChearProvider({ origin, children }: {
|
|
7
|
+
origin: string;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
10
|
+
interface CommonProps {
|
|
11
|
+
/** 채널 아이디 — 스튜디오에 보이는 @아이디(위젯 주소의 /embed/{아이디}/…) */
|
|
12
|
+
channel: string;
|
|
13
|
+
/** 간편 로그인(SSO) 토큰 — 파트너 회원으로 바로 채팅. 없으면 위젯 안 로그인 */
|
|
14
|
+
ssoToken?: string;
|
|
15
|
+
/** 위젯 출처 — ChearProvider 보다 우선 */
|
|
16
|
+
origin?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
style?: CSSProperties;
|
|
19
|
+
/** 런타임을 못 불러왔을 때(네트워크 · 사이트 CSP 등) */
|
|
20
|
+
onError?: (error: unknown) => void;
|
|
21
|
+
}
|
|
22
|
+
export type ChearPlayerProps = CommonProps & PlayerOptions;
|
|
23
|
+
export type ChearChatProps = CommonProps & ChatOptions;
|
|
24
|
+
/** 플레이어 — 기본 폭 100% · 16:9. `chat` 이면 오른쪽에 채팅 같이 */
|
|
25
|
+
export declare function ChearPlayer({ autoplay, muted, controls, chat, stats, ...common }: ChearPlayerProps): import("react").JSX.Element;
|
|
26
|
+
/** 채팅 — 실제로 채팅(위젯 안 로그인 · 이모티콘 · 신고). 기본 폭 100% · 부모 높이(없으면 최소 480px) */
|
|
27
|
+
export declare function ChearChat({ theme, ...common }: ChearChatProps): import("react").JSX.Element;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { DEFAULT_ORIGIN, loadRuntime } from "./loader";
|
|
5
|
+
export { DEFAULT_ORIGIN, loadRuntime, runtimeUrl } from "./loader";
|
|
6
|
+
/**
|
|
7
|
+
* 치어 위젯 — 플레이어 · 채팅을 리액트 컴포넌트로 (docs/design/embed-sdk.md).
|
|
8
|
+
* 화면은 위젯 출처의 런타임(`/sdk/v1/runtime.js`)이 그린다 — 스튜디오 › 위젯의 iframe 위젯과 같은 화면 · 같은 동작.
|
|
9
|
+
* 파트너 페이지 스타일과 섞이지 않게 컴포넌트의 div 안 Shadow DOM 에 그린다.
|
|
10
|
+
*/
|
|
11
|
+
const OriginContext = createContext(DEFAULT_ORIGIN);
|
|
12
|
+
/** 위젯 출처를 바꿀 때만(개발서버 · 다른 플랫폼). 운영 치어는 필요 없음 */
|
|
13
|
+
export function ChearProvider({ origin, children }) {
|
|
14
|
+
return _jsx(OriginContext.Provider, { value: origin, children: children });
|
|
15
|
+
}
|
|
16
|
+
/** 정의된 값만 — 없는 옵션은 위젯 기본값 */
|
|
17
|
+
function defined(value) {
|
|
18
|
+
return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined));
|
|
19
|
+
}
|
|
20
|
+
function Widget({ kind, channel, ssoToken, origin, className, style, onError, options, defaultStyle }) {
|
|
21
|
+
const fromContext = useContext(OriginContext);
|
|
22
|
+
const target = origin ?? fromContext;
|
|
23
|
+
const host = useRef(null);
|
|
24
|
+
const instance = useRef(null);
|
|
25
|
+
const [failed, setFailed] = useState(false);
|
|
26
|
+
const config = { kind, channel, options: defined(options), ssoToken };
|
|
27
|
+
const latest = useRef(config);
|
|
28
|
+
latest.current = config;
|
|
29
|
+
const onErrorRef = useRef(onError);
|
|
30
|
+
onErrorRef.current = onError;
|
|
31
|
+
// 출처마다 한 번 그린다 — 옵션 · 채널이 바뀌면 아래 update 로
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const el = host.current;
|
|
34
|
+
if (!el)
|
|
35
|
+
return;
|
|
36
|
+
let cancelled = false;
|
|
37
|
+
setFailed(false);
|
|
38
|
+
loadRuntime(target).then((runtime) => {
|
|
39
|
+
if (!cancelled)
|
|
40
|
+
instance.current = runtime.mount(el, latest.current);
|
|
41
|
+
}, (error) => {
|
|
42
|
+
if (cancelled)
|
|
43
|
+
return;
|
|
44
|
+
setFailed(true);
|
|
45
|
+
onErrorRef.current?.(error);
|
|
46
|
+
});
|
|
47
|
+
return () => {
|
|
48
|
+
cancelled = true;
|
|
49
|
+
instance.current?.unmount();
|
|
50
|
+
instance.current = null;
|
|
51
|
+
};
|
|
52
|
+
}, [target]);
|
|
53
|
+
const key = JSON.stringify(config);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
instance.current?.update(latest.current);
|
|
56
|
+
}, [key]);
|
|
57
|
+
return _jsx("div", { ref: host, className: className, style: { ...defaultStyle, ...style }, "data-chear-widget": kind, "data-failed": failed || undefined });
|
|
58
|
+
}
|
|
59
|
+
/** 플레이어 — 기본 폭 100% · 16:9. `chat` 이면 오른쪽에 채팅 같이 */
|
|
60
|
+
export function ChearPlayer({ autoplay, muted, controls, chat, stats, ...common }) {
|
|
61
|
+
return _jsx(Widget, { kind: "player", options: { autoplay, muted, controls, chat, stats }, defaultStyle: { display: "block", width: "100%", aspectRatio: "16 / 9" }, ...common });
|
|
62
|
+
}
|
|
63
|
+
/** 채팅 — 실제로 채팅(위젯 안 로그인 · 이모티콘 · 신고). 기본 폭 100% · 부모 높이(없으면 최소 480px) */
|
|
64
|
+
export function ChearChat({ theme, ...common }) {
|
|
65
|
+
return _jsx(Widget, { kind: "chat", options: { theme }, defaultStyle: { display: "block", width: "100%", height: "100%", minHeight: 480 }, ...common });
|
|
66
|
+
}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WidgetRuntime } from "./types";
|
|
2
|
+
/** 운영 위젯 출처 — 개발 · 다른 플랫폼은 <ChearProvider origin="…"> */
|
|
3
|
+
export declare const DEFAULT_ORIGIN = "https://player.chear.live";
|
|
4
|
+
/** 런타임 판 — 위젯 출처의 /sdk/v{N}/runtime.js */
|
|
5
|
+
export declare const RUNTIME_VERSION = 1;
|
|
6
|
+
/** `https://player.chear.live/` · 경로가 붙은 주소 → 출처만 */
|
|
7
|
+
export declare function normalizeOrigin(origin: string): string;
|
|
8
|
+
export declare const runtimeUrl: (origin: string) => string;
|
|
9
|
+
/**
|
|
10
|
+
* 런타임을 위젯 출처에서 한 번만 받는다(같은 출처면 컴포넌트 여러 개가 같이 씀).
|
|
11
|
+
* 화면은 런타임에 있어서 위젯이 바뀌면 이 패키지를 다시 받지 않아도 같이 바뀐다. 실패하면 다음 시도 때 다시 받는다
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadRuntime(origin?: string): Promise<WidgetRuntime>;
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** 운영 위젯 출처 — 개발 · 다른 플랫폼은 <ChearProvider origin="…"> */
|
|
2
|
+
export const DEFAULT_ORIGIN = "https://player.chear.live";
|
|
3
|
+
/** 런타임 판 — 위젯 출처의 /sdk/v{N}/runtime.js */
|
|
4
|
+
export const RUNTIME_VERSION = 1;
|
|
5
|
+
/** `https://player.chear.live/` · 경로가 붙은 주소 → 출처만 */
|
|
6
|
+
export function normalizeOrigin(origin) {
|
|
7
|
+
return new URL(origin).origin;
|
|
8
|
+
}
|
|
9
|
+
export const runtimeUrl = (origin) => `${normalizeOrigin(origin)}/sdk/v${RUNTIME_VERSION}/runtime.js`;
|
|
10
|
+
const loading = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* 런타임을 위젯 출처에서 한 번만 받는다(같은 출처면 컴포넌트 여러 개가 같이 씀).
|
|
13
|
+
* 화면은 런타임에 있어서 위젯이 바뀌면 이 패키지를 다시 받지 않아도 같이 바뀐다. 실패하면 다음 시도 때 다시 받는다
|
|
14
|
+
*/
|
|
15
|
+
export function loadRuntime(origin = DEFAULT_ORIGIN) {
|
|
16
|
+
const url = runtimeUrl(origin);
|
|
17
|
+
let pending = loading.get(url);
|
|
18
|
+
if (!pending) {
|
|
19
|
+
// 런타임 조각들이 실행되기 전에 "위젯 SDK 로 돈다 · 위젯 출처"를 알린다(런타임이 파트너 문서의 <html> 을 건드리지 않게)
|
|
20
|
+
const g = globalThis;
|
|
21
|
+
g.__CHEAR_SDK__ ?? (g.__CHEAR_SDK__ = { origin: normalizeOrigin(origin) });
|
|
22
|
+
pending = import(/* @vite-ignore */ /* webpackIgnore: true */ url).then((mod) => {
|
|
23
|
+
const runtime = mod.default;
|
|
24
|
+
if (!runtime || runtime.version !== RUNTIME_VERSION)
|
|
25
|
+
throw new Error(`치어 위젯 런타임을 불러오지 못했어요(${url})`);
|
|
26
|
+
return runtime;
|
|
27
|
+
});
|
|
28
|
+
pending.catch(() => loading.delete(url));
|
|
29
|
+
loading.set(url, pending);
|
|
30
|
+
}
|
|
31
|
+
return pending;
|
|
32
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 위젯 런타임과의 약속(v1) — 런타임 쪽 같은 모양: user-web `src/sdk/types.ts`. 바꾸면 둘 다 같이(docs/design/embed-sdk.md 2장)
|
|
3
|
+
*/
|
|
4
|
+
/** 플레이어 옵션 — 위젯 주소 쿼리와 같은 이름 · 같은 기본값 */
|
|
5
|
+
export interface PlayerOptions {
|
|
6
|
+
/** 자동 재생(기본 켬 — 브라우저 정책상 소리 끔과 함께만 확실) */
|
|
7
|
+
autoplay?: boolean;
|
|
8
|
+
/** 소리 끔(기본 켬) */
|
|
9
|
+
muted?: boolean;
|
|
10
|
+
/** 플레이어 컨트롤(기본 켬) */
|
|
11
|
+
controls?: boolean;
|
|
12
|
+
/** 오른쪽(좁은 세로 화면은 아래)에 채팅 같이(기본 끔) */
|
|
13
|
+
chat?: boolean;
|
|
14
|
+
/** 왼쪽 위 LIVE · 시청 중(기본 켬) */
|
|
15
|
+
stats?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** 채팅 옵션 */
|
|
18
|
+
export interface ChatOptions {
|
|
19
|
+
/** 다크(기본) · 라이트 */
|
|
20
|
+
theme?: "dark" | "light";
|
|
21
|
+
}
|
|
22
|
+
export type WidgetKind = "player" | "chat";
|
|
23
|
+
export interface WidgetConfig {
|
|
24
|
+
kind: WidgetKind;
|
|
25
|
+
channel: string;
|
|
26
|
+
options?: PlayerOptions | ChatOptions;
|
|
27
|
+
ssoToken?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface WidgetInstance {
|
|
30
|
+
update(config: WidgetConfig): void;
|
|
31
|
+
unmount(): void;
|
|
32
|
+
}
|
|
33
|
+
export interface WidgetRuntime {
|
|
34
|
+
version: 1;
|
|
35
|
+
origin: string;
|
|
36
|
+
mount(host: HTMLElement, config: WidgetConfig): WidgetInstance;
|
|
37
|
+
}
|
package/dist/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowsoft-lab/chear-widget-react",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "치어(CHEAR) 위젯 — 플레이어 · 채팅을 리액트 컴포넌트로. <ChearPlayer channel=\"…\" />",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"chear",
|
|
7
|
+
"react",
|
|
8
|
+
"live",
|
|
9
|
+
"streaming",
|
|
10
|
+
"player",
|
|
11
|
+
"chat",
|
|
12
|
+
"widget"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://www.chear.live/developers/api#widget-sdk",
|
|
15
|
+
"license": "UNLICENSED",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.build.json",
|
|
36
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"pack:sdk": "pnpm build && node scripts/pack-sdk.mjs",
|
|
39
|
+
"prepublishOnly": "pnpm build && pnpm test",
|
|
40
|
+
"release": "bash scripts/publish.sh"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"react": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/react": "^19.3.0",
|
|
47
|
+
"react": "^19.3.0",
|
|
48
|
+
"react-dom": "^19.3.0",
|
|
49
|
+
"vitest": "^5.0.3"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
}
|
|
54
|
+
}
|