@vibexnpm/talkx 5.3.0 → 5.6.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/dist/index.d.ts +93 -16
- 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 +1 -1
- package/src/TalkFlowClient.js +124 -0
- package/src/chat/ChatClient.js +28 -23
- package/src/constants.js +1 -1
- package/types/__typetests__/singleMessageAttachment.types.ts +22 -1
- package/types/index.d.ts +93 -16
package/package.json
CHANGED
package/src/TalkFlowClient.js
CHANGED
|
@@ -237,10 +237,134 @@ class TalkFlowClient extends EventEmitter {
|
|
|
237
237
|
|
|
238
238
|
// ==================== 사용자 API ====================
|
|
239
239
|
|
|
240
|
+
/**
|
|
241
|
+
* 회원 로그인 — 이메일/비밀번호로 채팅 접속 일체를 받는다. **클라이언트 생성 전에 호출한다.**
|
|
242
|
+
*
|
|
243
|
+
* <p>{@link #registerUser} 와 달리 Server Key 도 고객사 BFF 도 필요 없다. 응답의
|
|
244
|
+
* {@code clientKey}/{@code projectId}/{@code accessToken} 이 그대로 SDK 초기화 입력이다.</p>
|
|
245
|
+
*
|
|
246
|
+
* <p><b>회사 선택 단계가 없다</b>: 로그인 키가 전역 유일이라 이메일 하나로 회원과 회사가
|
|
247
|
+
* 함께 정해진다. 퇴사하면 그 키가 풀려 다른 회사에서 같은 이메일을 다시 쓸 수 있다.</p>
|
|
248
|
+
*
|
|
249
|
+
* @param {Object} options
|
|
250
|
+
* @param {string} options.serverUrl - 채팅 서버 base URL
|
|
251
|
+
* @param {string} options.email
|
|
252
|
+
* @param {string} options.password
|
|
253
|
+
* @returns {Promise<Object>} `{accessToken, tokenType, expiresIn, projectId, clientKey, user}`
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* const login = await TalkFlowClient.loginUser({
|
|
257
|
+
* serverUrl: 'https://chat.apiorbit.net',
|
|
258
|
+
* email: 'dan@example.com',
|
|
259
|
+
* password: '********'
|
|
260
|
+
* });
|
|
261
|
+
*
|
|
262
|
+
* const client = new TalkFlowClient({
|
|
263
|
+
* apiKey: login.clientKey,
|
|
264
|
+
* projectId: login.projectId,
|
|
265
|
+
* jwtToken: login.accessToken
|
|
266
|
+
* });
|
|
267
|
+
* await client.connect();
|
|
268
|
+
*/
|
|
269
|
+
static async loginUser({ serverUrl, email, password }) {
|
|
270
|
+
if (!serverUrl) throw new Error('serverUrl is required');
|
|
271
|
+
if (!email) throw new Error('email is required');
|
|
272
|
+
if (!password) throw new Error('password is required');
|
|
273
|
+
|
|
274
|
+
// 로그인은 키를 «받기 위해» 부르는 경로라 X-API-KEY/X-PROJECT-ID 가 없다(서버에서 필터 제외).
|
|
275
|
+
const client = new ApiClient({ baseUrl: serverUrl, apiKey: '', projectId: '' });
|
|
276
|
+
const response = await client.post('/api/v1/auth/login', { email, password });
|
|
277
|
+
return (response && response.data) ? response.data : response;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* 회원 로그인 (인스턴스) — 성공 시 JWT 를 자동 설정한다.
|
|
282
|
+
*
|
|
283
|
+
* <p>이미 클라이언트가 있는 상태의 재로그인·계정 전환용이다. 최초 진입은 클라이언트 생성 전에
|
|
284
|
+
* 부르는 정적 {@link TalkFlowClient.loginUser} 를 쓴다 — 그쪽이 {@code clientKey} 까지 준다.</p>
|
|
285
|
+
*
|
|
286
|
+
* @param {Object} credentials
|
|
287
|
+
* @param {string} credentials.email
|
|
288
|
+
* @param {string} credentials.password
|
|
289
|
+
* @returns {Promise<Object>} 로그인 응답
|
|
290
|
+
*/
|
|
291
|
+
async loginUser({ email, password }) {
|
|
292
|
+
const response = await this.apiClient.post('/api/v1/auth/login', { email, password });
|
|
293
|
+
const data = (response && response.data) ? response.data : response;
|
|
294
|
+
|
|
295
|
+
if (data && data.accessToken) {
|
|
296
|
+
await this.setToken(data.accessToken);
|
|
297
|
+
this.logger.info('Member logged in, token auto-set');
|
|
298
|
+
}
|
|
299
|
+
return data;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* 내 정보 조회.
|
|
304
|
+
*
|
|
305
|
+
* @returns {Promise<Object>} `{userId, email, name, phone, profileUrl, companyRole, orgNodeId, orgName, ...}`
|
|
306
|
+
*/
|
|
307
|
+
async getMyProfile() {
|
|
308
|
+
this._checkToken();
|
|
309
|
+
const response = await this.apiClient.get('/api/v1/me');
|
|
310
|
+
return (response && response.data) ? response.data : response;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* 내 정보 수정 — 이름·전화번호·프로필 이미지.
|
|
315
|
+
*
|
|
316
|
+
* <p>서버가 <b>새 JWT</b> 를 함께 준다: {@code name}/{@code profileUrl} 이 토큰 claim 이라
|
|
317
|
+
* 갱신하지 않으면 옛 값이 토큰 만료(7일)까지 계속 나간다. 여기서 자동 채택한다.</p>
|
|
318
|
+
*
|
|
319
|
+
* <p>이메일·조직·역할은 바꿀 수 없다 — 이메일은 로그인 키, 조직은 파트너가 정하고,
|
|
320
|
+
* 역할은 본인이 승급할 수 없어야 한다.</p>
|
|
321
|
+
*
|
|
322
|
+
* @param {Object} profile
|
|
323
|
+
* @param {string} [profile.name]
|
|
324
|
+
* @param {string} [profile.phone]
|
|
325
|
+
* @param {string} [profile.profileUrl]
|
|
326
|
+
* @returns {Promise<Object>} 갱신된 내 정보 (accessToken 포함)
|
|
327
|
+
*/
|
|
328
|
+
async updateMyProfile(profile) {
|
|
329
|
+
this._checkToken();
|
|
330
|
+
const response = await this.apiClient.put('/api/v1/me', profile);
|
|
331
|
+
const data = (response && response.data) ? response.data : response;
|
|
332
|
+
|
|
333
|
+
if (data && data.accessToken) {
|
|
334
|
+
// 토큰 교체 실패로 수정 자체를 실패시키지 않는다 — 서버 반영은 이미 끝났고 옛 토큰도
|
|
335
|
+
// 유효(낡았을 뿐)하므로 여기서 throw 하면 호출자가 이미 적용된 수정을 다시 시도한다.
|
|
336
|
+
try {
|
|
337
|
+
await this.setToken(data.accessToken);
|
|
338
|
+
} catch (error) {
|
|
339
|
+
this.logger.warn('Profile updated but token refresh failed; keeping the old token', error);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return data;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* 비밀번호 변경 — 현재 비밀번호를 재확인한다.
|
|
347
|
+
*
|
|
348
|
+
* <p>토큰만 탈취해도 비밀번호를 바꿀 수 있으면 계정을 통째로 빼앗긴다. 비밀번호는 바뀌어도
|
|
349
|
+
* 토큰은 그대로 유효하다 — 재로그인이 필요하지 않다.</p>
|
|
350
|
+
*
|
|
351
|
+
* @param {Object} params
|
|
352
|
+
* @param {string} params.currentPassword
|
|
353
|
+
* @param {string} params.newPassword - 8자 이상
|
|
354
|
+
*/
|
|
355
|
+
async changeMyPassword({ currentPassword, newPassword }) {
|
|
356
|
+
this._checkToken();
|
|
357
|
+
return this.apiClient.put('/api/v1/me/password', { currentPassword, newPassword });
|
|
358
|
+
}
|
|
359
|
+
|
|
240
360
|
/**
|
|
241
361
|
* 사용자 인증 (등록/로그인).
|
|
242
362
|
* 인증 성공 시 반환된 JWT 토큰을 자동으로 설정합니다.
|
|
243
363
|
*
|
|
364
|
+
* <h3>⚠️ DEPRECATED — {@link TalkFlowClient.loginUser} 로 대체</h3>
|
|
365
|
+
* <p>고객사 앱이 자기 회원 ID 를 들고 오던 경로다. 서버에서 {@code POST /api/v1/users/auth} 가
|
|
366
|
+
* 제거될 예정이며 그때 이 메서드도 함께 사라진다. 신규 코드는 {@code loginUser} 를 쓴다.</p>
|
|
367
|
+
*
|
|
244
368
|
* <h3>⚠️ Server API Key 전용</h3>
|
|
245
369
|
* <p>이 메서드는 JWT 를 발급하는 엔드포인트 ({@code POST /api/v1/users/auth}) 를 호출합니다.
|
|
246
370
|
* <strong>프로덕션 환경에서는 Client API Key 로 이 메서드를 호출하면 서버가 403 을 반환합니다.</strong></p>
|
package/src/chat/ChatClient.js
CHANGED
|
@@ -648,23 +648,24 @@ class ChatClient extends EventEmitter {
|
|
|
648
648
|
* @param {Object} [options]
|
|
649
649
|
* @param {string} [options.format] - 요약 포맷 ({@link SummarizeFormat}). 미지정/알 수 없는 값이면 서버가 {@code SHORT} 적용.
|
|
650
650
|
* @param {string} [options.lang] - 출력 언어(BCP-47 예 {@code 'ko'}/{@code 'en'}, 또는 {@code 'OFF'}=원문). 미지정 시 요청자 언어로 해소.
|
|
651
|
-
* @returns {Promise<{status: string, format?: string, language?: string}>} {@code status}: {@code '
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
* {@code format}/{@code language}=이번
|
|
655
|
-
*
|
|
656
|
-
* @
|
|
651
|
+
* @returns {Promise<{status: string, format?: string, language?: string}>} {@code status}: {@code 'QUEUED'} —
|
|
652
|
+
* 방 단위 durable work item 에 저장·병합됐다. local worker 포화여도 요청은 버려지지 않으며
|
|
653
|
+
* 최종 {@code READY|NO_CHANGE|NO_MESSAGES|FAILED} {@code summaryUpdate} 를 기다린다.
|
|
654
|
+
* {@code format}/{@code language}=이번 호출이 work item 에 병합한 키.
|
|
655
|
+
* ⚠️ 닫힌 목록이 아니다 — 분기에는 default 를 두고, 모르는 값에 스피너를 띄우지 마라.
|
|
656
|
+
* @throws {Error} HTTP 503 {@code SUMMARY_REFRESH_UNAVAILABLE} — durable 저장 자체가 실패했다.
|
|
657
|
+
* 간격을 두고 재시도하고 사용자에게는 일시 오류로 알린다.
|
|
658
|
+
* {@code err.status}=503, {@code err.response.code}={@code 'SUMMARY_REFRESH_UNAVAILABLE'}.
|
|
659
|
+
*
|
|
660
|
+
* @fires summaryUpdate - { roomId, status: 'READY'|'NO_CHANGE'|'NO_MESSAGES'|'FAILED'|'INVALIDATED'|string, format, languages, updatedAt }.
|
|
657
661
|
* fan-out 으로 여러 언어를 한 번에 생성하므로 {@code languages} 는 배열(§S1). {@code INVALIDATED} 는 refreshSummary 가
|
|
658
662
|
* 아니라 방 원문 삭제/편집으로 발생(요약이 통째로 폐기됨).
|
|
659
663
|
*
|
|
660
664
|
* @example
|
|
661
665
|
* const { status } = await chat.refreshSummary(roomId, { format: SummarizeFormat.MINUTES, lang: 'ko' });
|
|
662
|
-
* if (status === '
|
|
663
|
-
* else
|
|
664
|
-
*
|
|
665
|
-
* // 그때 다시 refreshSummary 로 내 언어를 요청한다(재요청 금지가 아니라 "내 언어가 없으면 재요청").
|
|
666
|
-
* showSpinner();
|
|
667
|
-
* } else if (status === 'NO_CHANGE') toast('변경 사항이 없습니다');
|
|
666
|
+
* if (status === 'QUEUED') showQueuedProgress(); // durable 접수 — summaryUpdate 대기
|
|
667
|
+
* else showUnknownSummaryState(status); // 미래 서버 값은 추측하지 않는다
|
|
668
|
+
* // 503(SUMMARY_REFRESH_UNAVAILABLE)은 durable 접수 실패 — try/catch로 받고 간격을 두고 재시도.
|
|
668
669
|
*/
|
|
669
670
|
async refreshSummary(roomId, options = {}) {
|
|
670
671
|
const { format, lang } = options;
|
|
@@ -678,9 +679,10 @@ class ChatClient extends EventEmitter {
|
|
|
678
679
|
/**
|
|
679
680
|
* Rolling 누적 요약 조회 — 통합본(rollup) + 구간 부분요약(segments) 페이지. 저장된 요약의 단일 진실 소스.
|
|
680
681
|
*
|
|
681
|
-
* <p>{@code summaryUpdate}
|
|
682
|
-
* transient(저장 안 됨)라 유실될 수 있으므로 GET 으로 동기화한다.
|
|
683
|
-
*
|
|
682
|
+
* <p>terminal {@code summaryUpdate} 수신 후, 화면 진입/재접속 시, 그리고 {@code QUEUED} 뒤 앱이 정한 완료
|
|
683
|
+
* timeout에 <b>한 번</b> 호출한다 — 알림은 transient(저장 안 됨)라 유실될 수 있으므로 GET 으로 동기화한다.
|
|
684
|
+
* 주기적 polling은 하지 않는다. 아직 한 번도 요약된 적 없으면 {@code rollup} 이 {@code null} 이다.
|
|
685
|
+
* segment 는 {@code afterSeq}/{@code size} 로 페이지네이션한다({@code hasNext}/{@code nextSeq}).</p>
|
|
684
686
|
*
|
|
685
687
|
* <p>같은 방을 여러 포맷×언어로 보관하므로 {@code options.format}/{@code options.lang} 으로 골라 조회한다.
|
|
686
688
|
* {@code lang} 미지정 시 서버가 요청자 언어로 해소하고, 응답 {@code language} 로 <b>어느 언어 기준</b>인지
|
|
@@ -694,7 +696,7 @@ class ChatClient extends EventEmitter {
|
|
|
694
696
|
* @param {string} [options.lang] - 조회할 언어(BCP-47 예 {@code 'ko'}, 또는 {@code 'OFF'}=원문). 미지정 시 요청자 언어로 해소(응답 {@code language}).
|
|
695
697
|
* @param {number} [options.afterSeq] - segment 페이지 커서(exclusive). 미지정 시 처음부터.
|
|
696
698
|
* @param {number} [options.size=50] - segment 페이지 크기(서버 상한 50).
|
|
697
|
-
* @returns {Promise<RoomSummaryView>} { language, rollup | null, availableFormats, segments, hasNext, nextSeq }
|
|
699
|
+
* @returns {Promise<RoomSummaryView>} { language, roomStatus, rollup | null, availableFormats, segments, hasNext, nextSeq }
|
|
698
700
|
*
|
|
699
701
|
* @example
|
|
700
702
|
* const view = await chat.getSummary(roomId, { format: 'timeline', lang: 'ko' });
|
|
@@ -3392,24 +3394,27 @@ class ChatClient extends EventEmitter {
|
|
|
3392
3394
|
/**
|
|
3393
3395
|
* Rolling 누적 요약 완료 알림(summary 채널) 수신 처리 — status 를 그대로 {@code summaryUpdate} 로 emit.
|
|
3394
3396
|
*
|
|
3395
|
-
* <p>서버 {@code SummaryStreamEvent}: {@code { status: 'READY'|'NO_CHANGE'|'FAILED'|'INVALIDATED', roomId, format?, languages?, updatedAt? }}.
|
|
3397
|
+
* <p>서버 {@code SummaryStreamEvent}: {@code { status: 'READY'|'NO_CHANGE'|'NO_MESSAGES'|'FAILED'|'INVALIDATED'|string, roomId, format?, languages?, updatedAt? }}.
|
|
3396
3398
|
* assistant-stream 과 달리 단계/토큰 누적이 없어 상태 관리 없이 그대로 통지한다. transient(저장 안 됨)라 UI 는
|
|
3397
3399
|
* 이벤트를 신호로만 쓰고 확정 내용은 {@link #getSummary} 로 읽는다. {@code READY}=요약 갱신됨(→ getSummary),
|
|
3398
|
-
* {@code FAILED}=실패(재시도 가능), {@code NO_CHANGE}
|
|
3400
|
+
* {@code FAILED}=실패(재시도 가능), {@code NO_CHANGE}=durable 작업이 변경 없이 완료,
|
|
3401
|
+
* {@code NO_MESSAGES}=해당 키에 요약할 대화 없음,
|
|
3399
3402
|
* {@code INVALIDATED}=방 원문 삭제/편집으로 요약이 통째로 버려짐(→ 요약 화면을 즉시 비우고, 필요 시 refreshSummary 로 재생성).</p>
|
|
3400
3403
|
*
|
|
3401
3404
|
* <p><b>키 식별(format+languages)</b>: 한 refresh 가 방 활성 언어들을 fan-out 으로 한 번에 생성하므로(§S1), 완료
|
|
3402
|
-
* 이벤트의 {@code languages} 에 내 언어가 있으면 {@code getSummary({ format, lang })} 로 읽는다.
|
|
3403
|
-
* {@code
|
|
3405
|
+
* 이벤트의 {@code languages} 에 내 언어가 있으면 {@code getSummary({ format, lang })} 로 읽는다.
|
|
3406
|
+
* {@code READY}·{@code NO_CHANGE}·{@code NO_MESSAGES}·{@code FAILED} 모두 언어 목록을 싣는다
|
|
3407
|
+
* ({@code INVALIDATED} 만 없음). 알 수 없는 미래 status도 그대로 전달하므로 소비자는 default 분기와
|
|
3408
|
+
* one-shot {@code getSummary} 재동기화를 둔다.</p>
|
|
3404
3409
|
* @private
|
|
3405
3410
|
*/
|
|
3406
3411
|
_handleSummaryEvent(roomId, event) {
|
|
3407
3412
|
if (!event || !event.status) return;
|
|
3408
3413
|
this.emit('summaryUpdate', {
|
|
3409
3414
|
roomId,
|
|
3410
|
-
status: event.status, //
|
|
3411
|
-
format: event.format || null, // READY/FAILED 포함
|
|
3412
|
-
languages: event.languages || null, //
|
|
3415
|
+
status: event.status, // known status + future server values (pass-through)
|
|
3416
|
+
format: event.format || null, // READY/NO_CHANGE/NO_MESSAGES/FAILED 포함
|
|
3417
|
+
languages: event.languages || null, // READY/NO_CHANGE/NO_MESSAGES/FAILED 처리 언어 목록
|
|
3413
3418
|
updatedAt: event.updatedAt || null
|
|
3414
3419
|
});
|
|
3415
3420
|
}
|
package/src/constants.js
CHANGED
|
@@ -364,7 +364,7 @@ export const WebSocketPaths = {
|
|
|
364
364
|
getChatTypingDestination: (roomId) => `/topic/chat/${roomId}/typing`,
|
|
365
365
|
// AI 진행 표시(생각중/검색중/작성중) + 토큰 스트리밍 — typing 과 별개 채널(가산 UX 레이어).
|
|
366
366
|
getChatAssistantStreamDestination: (roomId) => `/topic/chat/${roomId}/assistant-stream`,
|
|
367
|
-
// Rolling 누적 요약
|
|
367
|
+
// Rolling 누적 요약 종결 알림(READY/NO_CHANGE/NO_MESSAGES/FAILED) — refreshSummary 비동기 완료 채널.
|
|
368
368
|
getChatSummaryDestination: (roomId) => `/topic/chat/${roomId}/summary`,
|
|
369
369
|
|
|
370
370
|
// Room list (카톡 스타일 리스트 실시간 업데이트)
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
ChatMessage,
|
|
14
14
|
ChatMessageTypeValue,
|
|
15
15
|
FileMetaData,
|
|
16
|
+
RoomSummaryView,
|
|
16
17
|
SendFileInfo
|
|
17
18
|
} from '../index';
|
|
18
19
|
import { ChatMessageType } from '../index';
|
|
@@ -65,4 +66,24 @@ function legacyResponseFile(f: FileMetaData): string | undefined {
|
|
|
65
66
|
return f.fileId;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
// 7) 서버 rolling 배포를 견디도록 summary 상태는 열린 문자열 union이어야 한다.
|
|
70
|
+
function renderSummaryStatus(status: NonNullable<RoomSummaryView['roomStatus']>): string {
|
|
71
|
+
switch (status) {
|
|
72
|
+
case 'QUEUED': return 'queued';
|
|
73
|
+
case 'IDLE': return 'idle';
|
|
74
|
+
case 'RUNNING': return 'running';
|
|
75
|
+
case 'FAILED': return 'failed';
|
|
76
|
+
case 'NO_MESSAGES': return 'empty';
|
|
77
|
+
default: {
|
|
78
|
+
// @ts-expect-error 열린 union이므로 알려진 값만 처리해도 exhaustive never가 될 수 없다.
|
|
79
|
+
const futureServerStatus: never = status;
|
|
80
|
+
void futureServerStatus;
|
|
81
|
+
return 'unknown';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const futureSummaryStatus: NonNullable<RoomSummaryView['roomStatus']> = 'FUTURE_SERVER_STATUS';
|
|
87
|
+
|
|
88
|
+
export { category, viaTopLevel, mixed, gallery, document, render, uploadThenSend, optimistic, legacyResponseFile,
|
|
89
|
+
renderSummaryStatus, futureSummaryStatus };
|
package/types/index.d.ts
CHANGED
|
@@ -327,16 +327,20 @@ export interface RefreshSummaryOptions {
|
|
|
327
327
|
export interface RefreshSummaryResult {
|
|
328
328
|
/**
|
|
329
329
|
* <ul>
|
|
330
|
-
* <li>{@code '
|
|
331
|
-
*
|
|
332
|
-
* 로 내 키인지 확인하고, {@code summaryUpdate} 가 내 키가 아니면 그때 다시 요청한다(무조건 재요청 금지 아님).</li>
|
|
333
|
-
* <li>{@code 'NO_CHANGE'} — 새 대화 없음(알림 발생 안 함; 직전 실패가 있었다면 자동 복구됨).</li>
|
|
330
|
+
* <li>{@code 'QUEUED'} — 방 단위 durable work item 에 저장·병합됐다. pod 실행 슬롯이 포화여도
|
|
331
|
+
* 요청은 버려지지 않으며, 최종 {@code READY|NO_CHANGE|NO_MESSAGES|FAILED} {@code summaryUpdate} 를 기다린다.</li>
|
|
334
332
|
* </ul>
|
|
333
|
+
*
|
|
334
|
+
* <p>durable 저장 자체가 실패하면 성공 결과가 아니라 <b>HTTP 503</b>
|
|
335
|
+
* ({@code SUMMARY_REFRESH_UNAVAILABLE})으로 오며, {@link ChatClient.refreshSummary} 가 reject 한다.</p>
|
|
336
|
+
*
|
|
337
|
+
* <p>⚠️ <b>닫힌 union 이 아니다</b>: 서버가 값을 추가할 수 있으므로 분기에는 반드시 default 를 둔다.
|
|
338
|
+
* 모르는 값을 {@code QUEUED} 로 가정하지 말고 별도 상태 확인 UI를 표시한다.</p>
|
|
335
339
|
*/
|
|
336
|
-
status: '
|
|
337
|
-
/**
|
|
340
|
+
status: 'QUEUED' | (string & {});
|
|
341
|
+
/** durable work item 에 병합한 포맷({@link SummarizeFormat} 소문자). */
|
|
338
342
|
format?: string;
|
|
339
|
-
/**
|
|
343
|
+
/** durable work item 에 병합한 요청자 언어(소문자 BCP-47 / {@code 'OFF'}=원문). */
|
|
340
344
|
language?: string;
|
|
341
345
|
}
|
|
342
346
|
|
|
@@ -400,11 +404,15 @@ export interface RoomSummaryView {
|
|
|
400
404
|
*/
|
|
401
405
|
language: string;
|
|
402
406
|
/**
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
*
|
|
407
|
+
* 실행 상태 — {@code 'QUEUED'}(durable 대기) | {@code 'IDLE'}(유휴) |
|
|
408
|
+
* {@code 'RUNNING'}(요약 중) | {@code 'FAILED'}(선택 키 실패) |
|
|
409
|
+
* {@code 'NO_MESSAGES'}(선택 키에 요약할 대화 없음).
|
|
410
|
+
* 대기/실행은 방 단위이고 terminal 결과는 조회한 포맷×언어 키 기준이다. 특정 rollup 의 최신 여부는
|
|
411
|
+
* {@code rollup.stale} 로 판단한다. 요약 이력이 없어도 durable job 상태가 있으면 null이 아닐 수 있다.
|
|
412
|
+
* 닫힌 union이 아니므로 분기에는 default를 둔다.
|
|
406
413
|
*/
|
|
407
|
-
|
|
414
|
+
/** durable execution-plane 상태에서 합성되므로 재접속 뒤에도 복원된다. */
|
|
415
|
+
roomStatus: 'QUEUED' | 'IDLE' | 'RUNNING' | 'FAILED' | 'NO_MESSAGES' | (string & {}) | null;
|
|
408
416
|
/** 요청/기본 포맷의 통합 요약본. 그 포맷×언어로 아직 요약 안 됐으면 null(availableFormats 로 같은 언어의 다른 포맷 확인). */
|
|
409
417
|
rollup: RoomSummaryRollup | null;
|
|
410
418
|
/** 이 방이 <b>이 언어로</b> 보유한 포맷 목록(short/timeline/… — 탭 렌더용). 타 언어는 포함하지 않는다. */
|
|
@@ -424,15 +432,18 @@ export interface RoomSummaryView {
|
|
|
424
432
|
export interface SummaryUpdateEvent {
|
|
425
433
|
roomId: string;
|
|
426
434
|
/**
|
|
427
|
-
* {@code 'READY'}(갱신됨 → getSummary) | {@code 'FAILED'}(실패 → 재시도 가능) |
|
|
435
|
+
* {@code 'READY'}(갱신됨 → getSummary) | {@code 'FAILED'}(실패 → 재시도 가능) |
|
|
436
|
+
* {@code 'NO_CHANGE'}(변경 없이 durable 작업 종결 → getSummary로 최종 동기화) |
|
|
437
|
+
* {@code 'NO_MESSAGES'}(선택 키에 요약할 대화 없음) |
|
|
428
438
|
* {@code 'INVALIDATED'}(방 원문 삭제/편집으로 요약이 통째로 버려짐 → 화면을 비우고 필요 시 refreshSummary 로 재생성).
|
|
439
|
+
* 닫힌 union이 아니므로 모르는 값은 추측하지 말고 one-shot getSummary로 재동기화한다.
|
|
429
440
|
*/
|
|
430
|
-
status: 'READY' | 'NO_CHANGE' | 'FAILED' | 'INVALIDATED';
|
|
431
|
-
/**
|
|
441
|
+
status: 'READY' | 'NO_CHANGE' | 'NO_MESSAGES' | 'FAILED' | 'INVALIDATED' | (string & {});
|
|
442
|
+
/** 완료 포맷. {@code READY}·{@code NO_CHANGE}·{@code NO_MESSAGES}·{@code FAILED} 포함, {@code INVALIDATED} 는 null. */
|
|
432
443
|
format: string | null;
|
|
433
444
|
/**
|
|
434
|
-
* fan-out 으로 한 번에
|
|
435
|
-
*
|
|
445
|
+
* fan-out 으로 한 번에 처리한 언어 목록(소문자 BCP-47 / {@code 'OFF'}).
|
|
446
|
+
* {@code READY}·{@code NO_CHANGE}·{@code NO_MESSAGES}·{@code FAILED} 포함, {@code INVALIDATED} 만 null.
|
|
436
447
|
*/
|
|
437
448
|
languages: string[] | null;
|
|
438
449
|
/** 갱신 시각(epoch millis). {@code READY} 만 포함, 그 외 null. */
|
|
@@ -951,6 +962,48 @@ export interface DecisionResponse {
|
|
|
951
962
|
optionId: string;
|
|
952
963
|
}
|
|
953
964
|
|
|
965
|
+
/** 로그인한 회원. `userId` 는 메시지 발신자 식별과 같은 값이다. */
|
|
966
|
+
export interface LoginMember {
|
|
967
|
+
userId: string;
|
|
968
|
+
email?: string | null;
|
|
969
|
+
nickname?: string | null;
|
|
970
|
+
profileUrl?: string | null;
|
|
971
|
+
preferredLanguage?: string | null;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* `TalkFlowClient.loginUser` 응답.
|
|
976
|
+
*
|
|
977
|
+
* 회사 선택 단계가 없다 — 로그인 키가 전역 유일이라 이메일 하나로 회원과 회사가 함께 정해진다.
|
|
978
|
+
*/
|
|
979
|
+
export interface LoginResult {
|
|
980
|
+
accessToken: string;
|
|
981
|
+
tokenType: string;
|
|
982
|
+
expiresIn?: number;
|
|
983
|
+
projectId: string;
|
|
984
|
+
/** 회사의 활성 ck- 키. SDK 초기화의 `apiKey` 로 그대로 넣는다. */
|
|
985
|
+
clientKey: string;
|
|
986
|
+
user: LoginMember;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/** 내 정보. 수정 응답에는 `accessToken` 이 함께 온다(name/profileUrl 이 토큰 claim). */
|
|
990
|
+
export interface MyProfile {
|
|
991
|
+
userId: string;
|
|
992
|
+
email?: string | null;
|
|
993
|
+
name?: string | null;
|
|
994
|
+
phone?: string | null;
|
|
995
|
+
profileUrl?: string | null;
|
|
996
|
+
/** 회사 역할 — 방 역할(ParticipantResponse.role)과 다른 축이다. */
|
|
997
|
+
companyRole: 'PARTNER' | 'MEMBER';
|
|
998
|
+
orgNodeId?: string | null;
|
|
999
|
+
orgName?: string | null;
|
|
1000
|
+
preferredLanguage?: string | null;
|
|
1001
|
+
projectId: string;
|
|
1002
|
+
joinedAt?: string | null;
|
|
1003
|
+
accessToken?: string;
|
|
1004
|
+
expiresIn?: number;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
954
1007
|
/** 채팅방 참가자. */
|
|
955
1008
|
export interface ParticipantResponse {
|
|
956
1009
|
userId: string;
|
|
@@ -2240,6 +2293,30 @@ export default class TalkFlowClient implements SdkEventEmitter<TalkFlowClientEve
|
|
|
2240
2293
|
removeAllListeners(event?: keyof TalkFlowClientEvents): void;
|
|
2241
2294
|
listenerCount(event: keyof TalkFlowClientEvents): number;
|
|
2242
2295
|
|
|
2296
|
+
// 회원 인증 · 내 정보
|
|
2297
|
+
/**
|
|
2298
|
+
* 회원 로그인 — 클라이언트 생성 **전에** 호출한다. Server Key 도 고객사 BFF 도 필요 없다.
|
|
2299
|
+
* 응답의 `clientKey`/`projectId`/`accessToken` 이 그대로 SDK 초기화 입력이다.
|
|
2300
|
+
* 회사 선택 단계가 없다 — 로그인 키가 전역 유일이다.
|
|
2301
|
+
*/
|
|
2302
|
+
static loginUser(options: {
|
|
2303
|
+
serverUrl: string;
|
|
2304
|
+
email: string;
|
|
2305
|
+
password: string;
|
|
2306
|
+
}): Promise<LoginResult>;
|
|
2307
|
+
|
|
2308
|
+
/** 회원 로그인 (인스턴스) — 재로그인·계정 전환용. 성공 시 토큰을 자동 설정한다. */
|
|
2309
|
+
loginUser(credentials: { email: string; password: string }): Promise<LoginResult>;
|
|
2310
|
+
|
|
2311
|
+
/** 내 정보 조회. */
|
|
2312
|
+
getMyProfile(): Promise<MyProfile>;
|
|
2313
|
+
|
|
2314
|
+
/** 내 정보 수정 — 응답의 새 토큰을 자동 채택한다(name/profileUrl 이 토큰 claim). */
|
|
2315
|
+
updateMyProfile(profile: { name?: string; phone?: string; profileUrl?: string }): Promise<MyProfile>;
|
|
2316
|
+
|
|
2317
|
+
/** 비밀번호 변경 — 현재 비밀번호 재확인. 토큰은 그대로 유효해 재로그인이 필요 없다. */
|
|
2318
|
+
changeMyPassword(params: { currentPassword: string; newPassword: string }): Promise<unknown>;
|
|
2319
|
+
|
|
2243
2320
|
// Connection lifecycle
|
|
2244
2321
|
connect(jwt?: string, options?: ConnectOptions): Promise<void>;
|
|
2245
2322
|
disconnect(): Promise<void>;
|