@vibexnpm/talkx 8.13.0 → 9.1.0
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 +3 -2
- package/dist/index.d.ts +693 -155
- package/dist/talkflow-sdk.esm.js +1 -1
- package/dist/talkflow-sdk.esm.js.map +1 -1
- package/dist/talkflow-sdk.standalone.js +1 -1
- package/dist/talkflow-sdk.standalone.js.map +1 -1
- package/dist/talkflow-sdk.umd.js +1 -1
- package/dist/talkflow-sdk.umd.js.map +1 -1
- package/package.json +4 -2
- package/src/TalkFlowClient.js +13 -5
- package/src/chat/ChatClient.js +155 -0
- package/src/constants.js +39 -41
- package/src/core/ConnectionManager.js +11 -1
- package/src/index.js +4 -4
- package/src/talkflow/delegates.js +19 -23
- package/src/talkflow/eventForwarding.js +11 -23
- package/src/talkflow/session.js +37 -4
- package/src/utils/ApiClient.js +45 -41
- package/src/webrtc/CallLedger.js +135 -0
- package/src/webrtc/LiveKitMediaSession.js +1568 -0
- package/src/webrtc/WebRTCClient.js +909 -1068
- package/types/__typetests__/call.types.ts +101 -0
- package/types/__typetests__/scheduledReports.types.ts +138 -0
- package/types/index.d.ts +693 -155
- package/src/webrtc/MediaStreamManager.js +0 -478
- package/src/webrtc/PeerConnectionManager.js +0 -476
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 화상통화 타입(v9.0.0) — docs/webrtc.md 의 흐름이 <b>실제로 컴파일되는지</b>.
|
|
3
|
+
*
|
|
4
|
+
* <p>jest 는 `.d.ts` 를 보지 않는다. 문서가 약속한 모양(걸기·받기·거절·끝내기, 이벤트 내용, 상태·사유 값)이 선언과 맞는지 tsc 로
|
|
5
|
+
* 고정한다. P2P 시절 메서드(endCall·toggleVideo·getLocalStream 등)는 없어야 한다.</p>
|
|
6
|
+
*
|
|
7
|
+
* <p>실행: {@code npm run typecheck}</p>
|
|
8
|
+
*/
|
|
9
|
+
import TalkFlowClient, { CallKind, CallState, CallEventTypes, ErrorTypes } from '../index';
|
|
10
|
+
import type {
|
|
11
|
+
CallEndReason, CallStateValue, CurrentCall, IncomingCallEvent, CallTrackEvent, CallParticipation, RingingCall, WebRTCClient
|
|
12
|
+
} from '../index';
|
|
13
|
+
|
|
14
|
+
declare const talkflow: TalkFlowClient;
|
|
15
|
+
|
|
16
|
+
// 1) 받는 쪽 — 울림 알림 → 받기/거절, 울림 정지
|
|
17
|
+
talkflow.on('incomingCall', async (call: IncomingCallEvent) => {
|
|
18
|
+
if (call.kind === CallKind.DIRECT && talkflow.isInCall()) {
|
|
19
|
+
await talkflow.rejectCall(call.callRoomId, { reason: 'BUSY' });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const callRoomId: string = await talkflow.acceptCall(call.callRoomId, { video: true });
|
|
23
|
+
void callRoomId;
|
|
24
|
+
});
|
|
25
|
+
talkflow.on('ringStopped', ({ callRoomId, reason }) => {
|
|
26
|
+
const known: boolean = reason === 'answered_elsewhere' || reason === 'timeout';
|
|
27
|
+
void callRoomId; void known;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// 2) 거는 쪽 — 1:1·그룹
|
|
31
|
+
async function start(): Promise<void> {
|
|
32
|
+
const direct: string = await talkflow.callUser('user-1', { video: false });
|
|
33
|
+
const group: string = await talkflow.createGroupCall({ invitedUsers: ['a', 'b'], title: '주간 회의', maxParticipants: 8 });
|
|
34
|
+
void direct; void group;
|
|
35
|
+
await talkflow.cancelCall();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 3) 상태·트랙·끝
|
|
39
|
+
talkflow.on('callStateChanged', ({ state, reason }) => {
|
|
40
|
+
const s: CallStateValue = state;
|
|
41
|
+
if (s === CallState.ENDED) {
|
|
42
|
+
const r: CallEndReason | undefined = reason;
|
|
43
|
+
void r;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
talkflow.on('trackSubscribed', (event: CallTrackEvent) => {
|
|
47
|
+
const source: 'camera' | 'microphone' | 'screen' | 'screen_audio' | 'unknown' = event.source;
|
|
48
|
+
void source;
|
|
49
|
+
});
|
|
50
|
+
// docs/webrtc.md «영상·음성 붙이기» 그대로 — 트랙을 화면에 붙이고 떼는 것이 공개 타입으로 컴파일된다.
|
|
51
|
+
talkflow.on('trackSubscribed', ({ userId, track }) => {
|
|
52
|
+
const element = track.attach();
|
|
53
|
+
element.dataset.userId = userId;
|
|
54
|
+
document.getElementById('remote')?.appendChild(element);
|
|
55
|
+
});
|
|
56
|
+
talkflow.on('trackUnsubscribed', ({ track }) => {
|
|
57
|
+
track.detach().forEach(element => element.remove());
|
|
58
|
+
});
|
|
59
|
+
talkflow.on('localTrackPublished', ({ source, track }) => {
|
|
60
|
+
if (source === 'camera') {
|
|
61
|
+
document.getElementById('preview')?.appendChild(track.attach());
|
|
62
|
+
const video: HTMLMediaElement = track.attach(document.createElement('video'));
|
|
63
|
+
const detached: HTMLMediaElement = track.detach(video);
|
|
64
|
+
void detached;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
talkflow.on('callEnded', ({ reason }) => {
|
|
68
|
+
const r: CallEndReason = reason;
|
|
69
|
+
void r;
|
|
70
|
+
});
|
|
71
|
+
talkflow.on('callError', ({ code }) => {
|
|
72
|
+
const denied: boolean = code === ErrorTypes.MEDIA_ACCESS_DENIED || code === ErrorTypes.CALL_ALREADY_ACTIVE;
|
|
73
|
+
void denied;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// 4) 미디어·장치·조회
|
|
77
|
+
async function controls(webrtc: WebRTCClient): Promise<void> {
|
|
78
|
+
await webrtc.setCameraEnabled(false);
|
|
79
|
+
await webrtc.setMicrophoneEnabled(true);
|
|
80
|
+
await webrtc.startScreenShare();
|
|
81
|
+
await webrtc.stopScreenShare();
|
|
82
|
+
const cameras: MediaDeviceInfo[] = await webrtc.getDevices('videoinput');
|
|
83
|
+
const switched: boolean = await webrtc.switchDevice('videoinput', cameras[0].deviceId);
|
|
84
|
+
const current: CurrentCall | null = webrtc.getCurrentCall();
|
|
85
|
+
const ringing: RingingCall[] = webrtc.getRingingCalls();
|
|
86
|
+
const participation: CallParticipation = await webrtc.getParticipation('call-1');
|
|
87
|
+
const stillRinging: boolean = participation.ring === 'RINGING';
|
|
88
|
+
void switched; void current; void ringing; void stillRinging;
|
|
89
|
+
await webrtc.leaveCall();
|
|
90
|
+
await webrtc.endCallForAll();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 5) 이벤트 종류 상수
|
|
94
|
+
const invitation: 'call_invitation' = CallEventTypes.INVITATION;
|
|
95
|
+
void invitation; void start; void controls;
|
|
96
|
+
|
|
97
|
+
// 6) P2P 시절 메서드는 없다
|
|
98
|
+
// @ts-expect-error — v9.0.0 에서 지웠다
|
|
99
|
+
talkflow.endCall();
|
|
100
|
+
// @ts-expect-error — v9.0.0 에서 지웠다
|
|
101
|
+
talkflow.getLocalStream();
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 예약 보고 타입 — docs/scheduled-reports.md 예제가 <b>실제로 컴파일되는지</b>.
|
|
3
|
+
*
|
|
4
|
+
* <p>jest 는 `.d.ts` 를 보지 않는다. 문서가 약속한 모양(반환은 데이터만 · `spec` 은 `kind` 로 가른다 ·
|
|
5
|
+
* 주기는 `type` 으로 가른다 · 멱등 키는 필수 · 응답의 칸을 그대로 고치기에 다시 보낼 수 있다)이 선언과 맞는지 여기서 본다.</p>
|
|
6
|
+
*
|
|
7
|
+
* <p>실행: {@code npm run typecheck}</p>
|
|
8
|
+
*/
|
|
9
|
+
import TalkFlowClient from '../index';
|
|
10
|
+
import type {
|
|
11
|
+
ChatRoomTypeValue,
|
|
12
|
+
CreateScheduledReportData,
|
|
13
|
+
ScheduledReport,
|
|
14
|
+
ScheduledReportDetail,
|
|
15
|
+
ScheduledReportRoomOption,
|
|
16
|
+
ScheduledReportRun,
|
|
17
|
+
ScheduledReportSpec,
|
|
18
|
+
ScheduledTaskKind,
|
|
19
|
+
} from '../index';
|
|
20
|
+
|
|
21
|
+
declare const talkflow: TalkFlowClient;
|
|
22
|
+
declare const key: string;
|
|
23
|
+
|
|
24
|
+
// 1) 작업 칸은 kind 로 가른다 — 갈래마다 그 종류의 칸만 보이고, 빠진 갈래는 컴파일에서 막힌다.
|
|
25
|
+
function describeSpec(spec: ScheduledReportSpec): string {
|
|
26
|
+
switch (spec.kind) {
|
|
27
|
+
case 'RESEARCH':
|
|
28
|
+
return spec.instruction;
|
|
29
|
+
case 'ROOM_DIGEST':
|
|
30
|
+
return `${spec.sourceRoomId} ${spec.period} ${spec.format} ${spec.focus ?? ''}`;
|
|
31
|
+
default: {
|
|
32
|
+
const unreachable: never = spec;
|
|
33
|
+
return unreachable;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2) 문서의 만들기 흐름 — 종류 → 원천 방 → 보낼 방 → 만들기 → 전용 방 초대. 반환은 데이터만이다.
|
|
39
|
+
async function createDigest(): Promise<ScheduledReport | null> {
|
|
40
|
+
const kinds: ScheduledTaskKind[] = await talkflow.getScheduledReportKinds();
|
|
41
|
+
if (!kinds.includes('ROOM_DIGEST')) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const sources: ScheduledReportRoomOption[] = await talkflow.getScheduledReportSourceRooms();
|
|
45
|
+
const sourceRoomId = sources[0].roomId;
|
|
46
|
+
const label: string = sources[0].name ?? sourceRoomId;
|
|
47
|
+
const roomType: ChatRoomTypeValue | undefined = sources[0].roomType;
|
|
48
|
+
const targets = await talkflow.getScheduledReportDeliveryRooms({ kind: 'ROOM_DIGEST', sourceRoomId });
|
|
49
|
+
const form: CreateScheduledReportData = {
|
|
50
|
+
title: '개발팀 주간 정리',
|
|
51
|
+
spec: { kind: 'ROOM_DIGEST', sourceRoomId, period: 'LAST_7_DAYS', format: 'MINUTES', focus: '결정 사항' },
|
|
52
|
+
cadence: { type: 'WEEKLY', days: ['MONDAY', 'THURSDAY'], time: '09:00', zoneId: 'Asia/Seoul' },
|
|
53
|
+
deliveryRoomIds: targets.map((room) => room.roomId),
|
|
54
|
+
};
|
|
55
|
+
const report = await talkflow.createScheduledReport(form, { idempotencyKey: key });
|
|
56
|
+
await talkflow.inviteToGroupRoom(report.homeRoomId, ['user-id']);
|
|
57
|
+
void [label, roomType];
|
|
58
|
+
return report;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 3) 자료조사 — 보낼 방은 생략할 수 있고, 매일·평일 주기는 요일이 없다.
|
|
62
|
+
async function createResearch(): Promise<ScheduledReport> {
|
|
63
|
+
const targets = await talkflow.getScheduledReportDeliveryRooms({ kind: 'RESEARCH' });
|
|
64
|
+
void targets;
|
|
65
|
+
return talkflow.createScheduledReport({
|
|
66
|
+
title: '아침 시장 조사',
|
|
67
|
+
spec: { kind: 'RESEARCH', instruction: '전기차 시장 소식 정리' },
|
|
68
|
+
cadence: { type: 'WEEKDAYS', time: '08:30' },
|
|
69
|
+
}, { idempotencyKey: key });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 4) 고치기 — 고칠 칸만 보낸다. 응답의 작업 칸·주기를 그대로 다시 보낼 수 있고, 고치기 화면의 보낼 방은 예약 id 로 고른다.
|
|
73
|
+
async function edit(report: ScheduledReport): Promise<void> {
|
|
74
|
+
await talkflow.updateScheduledReport(report.id, { status: 'PAUSED' });
|
|
75
|
+
await talkflow.updateScheduledReport(report.id, { status: 'ACTIVE' });
|
|
76
|
+
await talkflow.updateScheduledReport(report.id, { title: '새 제목', deliveryRoomIds: [] });
|
|
77
|
+
await talkflow.updateScheduledReport(report.id, { spec: report.spec, cadence: report.cadence });
|
|
78
|
+
await talkflow.updateScheduledReport(report.id, { cadence: { ...report.cadence, time: '10:00' } });
|
|
79
|
+
const rooms = await talkflow.getScheduledReportDeliveryRooms({ reportId: report.id });
|
|
80
|
+
const done: void = await talkflow.deleteScheduledReport(report.id);
|
|
81
|
+
void [rooms, done];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 5) 예약 목록과 상세 — 응답의 주기는 요일·시간대가 늘 있고, 회차의 사유·결과는 비어 있을 수 있다.
|
|
85
|
+
async function show(): Promise<string[]> {
|
|
86
|
+
const reports: ScheduledReport[] = await talkflow.getScheduledReports();
|
|
87
|
+
const detail: ScheduledReportDetail = await talkflow.getScheduledReport(reports[0].id);
|
|
88
|
+
const zoneId: string = detail.report.cadence.zoneId;
|
|
89
|
+
const days: number = detail.report.cadence.days.length;
|
|
90
|
+
const pauseReason: string = detail.report.pauseReason ?? '';
|
|
91
|
+
const next: string = detail.report.nextRunAt;
|
|
92
|
+
void [zoneId, days, pauseReason, next];
|
|
93
|
+
return detail.recentRuns.map((run: ScheduledReportRun) => {
|
|
94
|
+
const reason: string = run.endReason ?? '';
|
|
95
|
+
const kind: string = run.resultKind ?? '';
|
|
96
|
+
const skipped = run.deliveries.filter((delivery) => delivery.state === 'SKIPPED').map((delivery) => delivery.skipReason ?? '');
|
|
97
|
+
return `${run.scheduledAt} ${run.state} ${reason} ${kind} ${run.resultMessageId ?? ''} ${skipped.join(',')}`;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 6) 잘못된 칸 조합은 컴파일에서 막힌다.
|
|
102
|
+
async function rejected(sourceRoomId: string): Promise<void> {
|
|
103
|
+
const cadence = { type: 'DAILY', time: '09:00' } as const;
|
|
104
|
+
|
|
105
|
+
// @ts-expect-error — 멱등 키는 필수다. SDK 가 대신 만들지 않는다.
|
|
106
|
+
await talkflow.createScheduledReport({ title: 't', spec: { kind: 'RESEARCH', instruction: 'i' }, cadence });
|
|
107
|
+
|
|
108
|
+
// @ts-expect-error — 방 정리에는 원천 방이 있어야 한다.
|
|
109
|
+
const noSource: ScheduledReportSpec = { kind: 'ROOM_DIGEST', period: 'LAST_24_HOURS', format: 'SHORT' };
|
|
110
|
+
|
|
111
|
+
// @ts-expect-error — 자료조사에는 원천 방 칸이 없다.
|
|
112
|
+
const researchSource: ScheduledReportSpec = { kind: 'RESEARCH', instruction: 'i', sourceRoomId };
|
|
113
|
+
|
|
114
|
+
// @ts-expect-error — 형식은 공용 요약 형식 다섯 개뿐이다.
|
|
115
|
+
const wrongFormat: ScheduledReportSpec = { kind: 'ROOM_DIGEST', sourceRoomId, period: 'LAST_7_DAYS', format: 'BRIEF' };
|
|
116
|
+
|
|
117
|
+
// @ts-expect-error — 기간은 지난 24시간·지난 7일뿐이다.
|
|
118
|
+
const wrongPeriod: ScheduledReportSpec = { kind: 'ROOM_DIGEST', sourceRoomId, period: 'LAST_30_DAYS', format: 'SHORT' };
|
|
119
|
+
|
|
120
|
+
// @ts-expect-error — 없는 종류.
|
|
121
|
+
await talkflow.getScheduledReportDeliveryRooms({ kind: 'WEBPAGE_DIGEST' });
|
|
122
|
+
|
|
123
|
+
// @ts-expect-error — 방 정리의 보낼 방은 원천 방이 있어야 고른다.
|
|
124
|
+
await talkflow.getScheduledReportDeliveryRooms({ kind: 'ROOM_DIGEST' });
|
|
125
|
+
|
|
126
|
+
// @ts-expect-error — 주간은 요일이 있어야 한다.
|
|
127
|
+
await talkflow.updateScheduledReport('id', { cadence: { type: 'WEEKLY', time: '09:00' } });
|
|
128
|
+
|
|
129
|
+
// @ts-expect-error — 매일은 요일을 받지 않는다.
|
|
130
|
+
await talkflow.updateScheduledReport('id', { cadence: { type: 'DAILY', days: ['MONDAY'], time: '09:00' } });
|
|
131
|
+
|
|
132
|
+
// @ts-expect-error — 상태는 ACTIVE·PAUSED 뿐이다.
|
|
133
|
+
await talkflow.updateScheduledReport('id', { status: 'DELETED' });
|
|
134
|
+
|
|
135
|
+
void [noSource, researchSource, wrongFormat, wrongPeriod];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
void [describeSpec, createDigest, createResearch, edit, show, rejected];
|