@vibexnpm/talkx 5.4.0 → 6.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/dist/index.d.ts +115 -3
- 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 +140 -71
- package/src/chat/ChatClient.js +1 -1
- package/src/index.js +11 -19
- package/src/talkflow/session.js +3 -3
- package/types/index.d.ts +115 -3
package/package.json
CHANGED
package/src/TalkFlowClient.js
CHANGED
|
@@ -35,15 +35,11 @@ class TalkFlowClient extends EventEmitter {
|
|
|
35
35
|
* @param {number} [options.logLevel=LogLevel.WARN] - 로그 레벨
|
|
36
36
|
*
|
|
37
37
|
* @example
|
|
38
|
-
* // 1단계:
|
|
39
|
-
* //
|
|
40
|
-
* //
|
|
41
|
-
* // Body: { userId: 'user-123', nickname: '홍길동' }
|
|
42
|
-
* // Response: { accessToken, refreshToken }
|
|
38
|
+
* // 1단계: 로그인 — 클라이언트 생성 «전» 에 부른다. ck/projectId/JWT 를 한 번에 받는다.
|
|
39
|
+
* // const { clientKey, projectId, accessToken } = await TalkFlowClient.loginUser({
|
|
40
|
+
* // serverUrl, email, password });
|
|
43
41
|
*
|
|
44
|
-
* // 2단계:
|
|
45
|
-
*
|
|
46
|
-
* // 3단계: 브라우저에서 SDK 초기화
|
|
42
|
+
* // 2단계: 받은 값으로 SDK 초기화
|
|
47
43
|
* const client = new TalkFlowClient({
|
|
48
44
|
* apiKey: 'CLIENT_KEY', // 브라우저에 노출되는 Client Key
|
|
49
45
|
* projectId: 'your-project-id',
|
|
@@ -174,24 +170,13 @@ class TalkFlowClient extends EventEmitter {
|
|
|
174
170
|
throw new Error('projectId is required');
|
|
175
171
|
}
|
|
176
172
|
|
|
177
|
-
// Server Key (sk-)
|
|
178
|
-
//
|
|
179
|
-
// - staging/production: 경고 + 강력 안내
|
|
173
|
+
// Server Key (sk-) 는 SDK 가 쓸 일이 없다 — 유일한 용도였던 registerUser(/users/auth) 가
|
|
174
|
+
// 사라졌다. 그래도 들어오면 잘못된 키를 넣은 것이므로 알린다.
|
|
180
175
|
if (options.apiKey.startsWith('sk-')) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
'프로덕션 배포 전에 반드시 Client Key (ck-) 로 교체하세요.'
|
|
186
|
-
);
|
|
187
|
-
} else {
|
|
188
|
-
console.error(
|
|
189
|
-
'🚨 [TalkFlow] Server Key (sk-) 가 비개발 환경 (' + env + ') 에서 감지되었습니다. ' +
|
|
190
|
-
'보안 위험: Server Key 를 브라우저에 포함하면 공격자가 임의 사용자로 JWT 를 발급받을 수 있습니다. ' +
|
|
191
|
-
'반드시 Client Key (ck-) 로 교체하세요. ' +
|
|
192
|
-
'서버에서도 프로덕션 모드에서 Server Key 의 브라우저 호출을 차단합니다.'
|
|
193
|
-
);
|
|
194
|
-
}
|
|
176
|
+
console.error(
|
|
177
|
+
'🚨 [TalkFlow] Server Key (sk-) 로 SDK 를 초기화했습니다. ' +
|
|
178
|
+
'SDK 는 Client Key (ck-) 만 사용합니다 — loginUser() 응답의 clientKey 를 그대로 쓰세요.'
|
|
179
|
+
);
|
|
195
180
|
}
|
|
196
181
|
}
|
|
197
182
|
|
|
@@ -238,57 +223,123 @@ class TalkFlowClient extends EventEmitter {
|
|
|
238
223
|
// ==================== 사용자 API ====================
|
|
239
224
|
|
|
240
225
|
/**
|
|
241
|
-
*
|
|
242
|
-
* 인증 성공 시 반환된 JWT 토큰을 자동으로 설정합니다.
|
|
226
|
+
* 회원 로그인 — 이메일/비밀번호로 채팅 접속 일체를 받는다. **클라이언트 생성 전에 호출한다.**
|
|
243
227
|
*
|
|
244
|
-
* <
|
|
245
|
-
*
|
|
246
|
-
* <strong>프로덕션 환경에서는 Client API Key 로 이 메서드를 호출하면 서버가 403 을 반환합니다.</strong></p>
|
|
228
|
+
* <p>Server Key 도 고객사 BFF 도 필요 없다. 응답의
|
|
229
|
+
* {@code clientKey}/{@code projectId}/{@code accessToken} 이 그대로 SDK 초기화 입력이다.</p>
|
|
247
230
|
*
|
|
248
|
-
* <
|
|
249
|
-
*
|
|
250
|
-
* <li><strong>프로덕션</strong>: 고객사 backend 에서 Server Key 로 직접 {@code POST /api/v1/users/auth} 를 호출 →
|
|
251
|
-
* JWT 를 받아 SDK 에 {@code setToken(jwt)} 으로 전달. 이 메서드를 브라우저에서 쓰지 마세요.</li>
|
|
252
|
-
* </ul>
|
|
231
|
+
* <p><b>회사 선택 단계가 없다</b>: 로그인 키가 전역 유일이라 이메일 하나로 회원과 회사가
|
|
232
|
+
* 함께 정해진다. 퇴사하면 그 키가 풀려 다른 회사에서 같은 이메일을 다시 쓸 수 있다.</p>
|
|
253
233
|
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
* @param {
|
|
257
|
-
* @param {string}
|
|
258
|
-
* @
|
|
259
|
-
* @param {string} [userData.profileImageUrl] - 프로필 이미지 URL (max 500자)
|
|
260
|
-
* @param {Object} [userData.metadata] - 추가 메타데이터
|
|
261
|
-
* @returns {Promise<Object>} 인증 결과 (토큰 포함)
|
|
234
|
+
* @param {Object} options
|
|
235
|
+
* @param {string} options.serverUrl - 채팅 서버 base URL
|
|
236
|
+
* @param {string} options.email
|
|
237
|
+
* @param {string} options.password
|
|
238
|
+
* @returns {Promise<Object>} `{accessToken, tokenType, expiresIn, projectId, clientKey, user}`
|
|
262
239
|
*
|
|
263
240
|
* @example
|
|
264
|
-
*
|
|
241
|
+
* const login = await TalkFlowClient.loginUser({
|
|
242
|
+
* serverUrl: 'https://chat.apiorbit.net',
|
|
243
|
+
* email: 'dan@example.com',
|
|
244
|
+
* password: '********'
|
|
245
|
+
* });
|
|
246
|
+
*
|
|
265
247
|
* const client = new TalkFlowClient({
|
|
266
|
-
* apiKey:
|
|
267
|
-
* projectId:
|
|
268
|
-
*
|
|
248
|
+
* apiKey: login.clientKey,
|
|
249
|
+
* projectId: login.projectId,
|
|
250
|
+
* jwtToken: login.accessToken
|
|
269
251
|
* });
|
|
270
|
-
* await client.registerUser({ userId: 'user-123', nickname: '홍길동' });
|
|
271
252
|
* await client.connect();
|
|
272
253
|
*/
|
|
273
|
-
async
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
254
|
+
static async loginUser({ serverUrl, email, password }) {
|
|
255
|
+
if (!serverUrl) throw new Error('serverUrl is required');
|
|
256
|
+
if (!email) throw new Error('email is required');
|
|
257
|
+
if (!password) throw new Error('password is required');
|
|
258
|
+
|
|
259
|
+
// 로그인은 키를 «받기 위해» 부르는 경로라 X-API-KEY/X-PROJECT-ID 가 없다(서버에서 필터 제외).
|
|
260
|
+
const client = new ApiClient({ baseUrl: serverUrl, apiKey: '', projectId: '' });
|
|
261
|
+
const response = await client.post('/api/v1/auth/login', { email, password });
|
|
262
|
+
return (response && response.data) ? response.data : response;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* 회원 로그인 (인스턴스) — 성공 시 JWT 를 자동 설정한다.
|
|
267
|
+
*
|
|
268
|
+
* <p>이미 클라이언트가 있는 상태의 재로그인·계정 전환용이다. 최초 진입은 클라이언트 생성 전에
|
|
269
|
+
* 부르는 정적 {@link TalkFlowClient.loginUser} 를 쓴다 — 그쪽이 {@code clientKey} 까지 준다.</p>
|
|
270
|
+
*
|
|
271
|
+
* @param {Object} credentials
|
|
272
|
+
* @param {string} credentials.email
|
|
273
|
+
* @param {string} credentials.password
|
|
274
|
+
* @returns {Promise<Object>} 로그인 응답
|
|
275
|
+
*/
|
|
276
|
+
async loginUser({ email, password }) {
|
|
277
|
+
const response = await this.apiClient.post('/api/v1/auth/login', { email, password });
|
|
278
|
+
const data = (response && response.data) ? response.data : response;
|
|
279
|
+
|
|
280
|
+
if (data && data.accessToken) {
|
|
281
|
+
await this.setToken(data.accessToken);
|
|
282
|
+
this.logger.info('Member logged in, token auto-set');
|
|
282
283
|
}
|
|
284
|
+
return data;
|
|
285
|
+
}
|
|
283
286
|
|
|
284
|
-
|
|
287
|
+
/**
|
|
288
|
+
* 내 정보 조회.
|
|
289
|
+
*
|
|
290
|
+
* @returns {Promise<Object>} `{userId, email, name, phone, profileUrl, companyRole, orgNodeId, orgName, ...}`
|
|
291
|
+
*/
|
|
292
|
+
async getMyProfile() {
|
|
293
|
+
this._checkToken();
|
|
294
|
+
const response = await this.apiClient.get('/api/v1/me');
|
|
295
|
+
return (response && response.data) ? response.data : response;
|
|
296
|
+
}
|
|
285
297
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
298
|
+
/**
|
|
299
|
+
* 내 정보 수정 — 이름·전화번호·프로필 이미지.
|
|
300
|
+
*
|
|
301
|
+
* <p>서버가 <b>새 JWT</b> 를 함께 준다: {@code name}/{@code profileUrl} 이 토큰 claim 이라
|
|
302
|
+
* 갱신하지 않으면 옛 값이 토큰 만료(7일)까지 계속 나간다. 여기서 자동 채택한다.</p>
|
|
303
|
+
*
|
|
304
|
+
* <p>이메일·조직·역할은 바꿀 수 없다 — 이메일은 로그인 키, 조직은 파트너가 정하고,
|
|
305
|
+
* 역할은 본인이 승급할 수 없어야 한다.</p>
|
|
306
|
+
*
|
|
307
|
+
* @param {Object} profile
|
|
308
|
+
* @param {string} [profile.name]
|
|
309
|
+
* @param {string} [profile.phone]
|
|
310
|
+
* @param {string} [profile.profileUrl]
|
|
311
|
+
* @returns {Promise<Object>} 갱신된 내 정보 (accessToken 포함)
|
|
312
|
+
*/
|
|
313
|
+
async updateMyProfile(profile) {
|
|
314
|
+
this._checkToken();
|
|
315
|
+
const response = await this.apiClient.put('/api/v1/me', profile);
|
|
316
|
+
const data = (response && response.data) ? response.data : response;
|
|
317
|
+
|
|
318
|
+
if (data && data.accessToken) {
|
|
319
|
+
// 토큰 교체 실패로 수정 자체를 실패시키지 않는다 — 서버 반영은 이미 끝났고 옛 토큰도
|
|
320
|
+
// 유효(낡았을 뿐)하므로 여기서 throw 하면 호출자가 이미 적용된 수정을 다시 시도한다.
|
|
321
|
+
try {
|
|
322
|
+
await this.setToken(data.accessToken);
|
|
323
|
+
} catch (error) {
|
|
324
|
+
this.logger.warn('Profile updated but token refresh failed; keeping the old token', error);
|
|
325
|
+
}
|
|
289
326
|
}
|
|
327
|
+
return data;
|
|
328
|
+
}
|
|
290
329
|
|
|
291
|
-
|
|
330
|
+
/**
|
|
331
|
+
* 비밀번호 변경 — 현재 비밀번호를 재확인한다.
|
|
332
|
+
*
|
|
333
|
+
* <p>토큰만 탈취해도 비밀번호를 바꿀 수 있으면 계정을 통째로 빼앗긴다. 비밀번호는 바뀌어도
|
|
334
|
+
* 토큰은 그대로 유효하다 — 재로그인이 필요하지 않다.</p>
|
|
335
|
+
*
|
|
336
|
+
* @param {Object} params
|
|
337
|
+
* @param {string} params.currentPassword
|
|
338
|
+
* @param {string} params.newPassword - 8자 이상
|
|
339
|
+
*/
|
|
340
|
+
async changeMyPassword({ currentPassword, newPassword }) {
|
|
341
|
+
this._checkToken();
|
|
342
|
+
return this.apiClient.put('/api/v1/me/password', { currentPassword, newPassword });
|
|
292
343
|
}
|
|
293
344
|
|
|
294
345
|
/**
|
|
@@ -344,7 +395,9 @@ class TalkFlowClient extends EventEmitter {
|
|
|
344
395
|
* 지역 변형을 그대로 보내면 명시 요청({@code lang: 'en'})과 키가 분열되어 같은 언어 이중 생성·조회 miss 가
|
|
345
396
|
* 발생한다. 서버 {@code LanguageCode} 도 동일 규칙으로 축약하므로 어느 쪽으로 들어와도 같은 값이 된다.</p>
|
|
346
397
|
*
|
|
347
|
-
* <p
|
|
398
|
+
* <p>예전에는 {@code registerUser} 가 이 값을 자동으로 실어 보냈는데 그 경로가 사라졌다.
|
|
399
|
+
* 지금은 호출자가 직접 감지해 {@code PUT /api/v1/users/update} 의 {@code preferredLanguage}
|
|
400
|
+
* 로 넣어야 한다 — 넣지 않으면 사용자 기본 언어가 미설정으로 남아 자동 번역이 서버 기본값을 쓴다.</p>
|
|
348
401
|
* @returns {string|null}
|
|
349
402
|
*/
|
|
350
403
|
static detectBrowserLanguage() {
|
|
@@ -398,16 +451,32 @@ class TalkFlowClient extends EventEmitter {
|
|
|
398
451
|
}
|
|
399
452
|
|
|
400
453
|
/**
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
454
|
+
* 회사 조직도 + 인원 — <b>방 만들 때 «조직으로 초대»</b> 가 쓴다.
|
|
455
|
+
*
|
|
456
|
+
* <p>조직을 고르면 <b>하위 조직 인원까지</b> 초대된다. 그래서 각 노드의 {@code memberCount} 는
|
|
457
|
+
* 자손을 포함한 누적이고, {@code members} 는 그 노드 <b>직속</b>만이다 — 누적 목록이 필요하면
|
|
458
|
+
* {@code children} 을 따라 내려가며 모은다(상위마다 중복해 실으면 응답이 제곱으로 커진다).</p>
|
|
459
|
+
*
|
|
460
|
+
* <p>부서가 없는 회원은 {@code unassignedMembers} 에 있다. 퇴사·차단 회원은 어디에도 없다.</p>
|
|
461
|
+
*
|
|
462
|
+
* @returns {Promise<Object>} `{tree, unassignedMembers, totalMemberCount, membersOmitted}`
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* const dir = await client.getCompanyDirectory();
|
|
466
|
+
* // 조직 하나를 고르면 그 자손까지 전부 모은다
|
|
467
|
+
* const collect = (node) => [...node.members, ...node.children.flatMap(collect)];
|
|
404
468
|
*/
|
|
405
|
-
async
|
|
406
|
-
|
|
469
|
+
async getCompanyDirectory() {
|
|
470
|
+
this._checkToken();
|
|
471
|
+
return this.apiClient.get('/api/v1/company/directory');
|
|
407
472
|
}
|
|
408
473
|
|
|
409
474
|
/**
|
|
410
475
|
* 사용자 목록 조회
|
|
476
|
+
*
|
|
477
|
+
* <p>응답 행에 {@code phone}/{@code orgNodeId}/{@code orgName} 이 포함된다 — 부서명은
|
|
478
|
+
* 저장값이 아니라 조회 시점에 조직 마스터에서 해소한 값이다.</p>
|
|
479
|
+
*
|
|
411
480
|
* @param {Object} [params]
|
|
412
481
|
* @param {number} [params.size=50] - 페이지 크기 (1-100)
|
|
413
482
|
* @param {string} [params.lastId] - 마지막 사용자 ID
|
|
@@ -441,9 +510,9 @@ class TalkFlowClient extends EventEmitter {
|
|
|
441
510
|
_checkToken() {
|
|
442
511
|
if (!this.options.jwtToken) {
|
|
443
512
|
throw new Error(
|
|
444
|
-
'JWT token is required for this operation.
|
|
445
|
-
'(
|
|
446
|
-
'See README "
|
|
513
|
+
'JWT token is required for this operation. Sign in with ' +
|
|
514
|
+
'TalkFlowClient.loginUser({ serverUrl, email, password }) and pass the ' +
|
|
515
|
+
'returned accessToken via setToken(). See README "로그인".'
|
|
447
516
|
);
|
|
448
517
|
}
|
|
449
518
|
}
|
package/src/chat/ChatClient.js
CHANGED
|
@@ -376,7 +376,7 @@ class ChatClient extends EventEmitter {
|
|
|
376
376
|
|
|
377
377
|
/**
|
|
378
378
|
* 1:1 채팅방 생성/조회
|
|
379
|
-
* @param {string} friendId - 상대방 사용자 ID (
|
|
379
|
+
* @param {string} friendId - 상대방 사용자 ID (서버 내부 {@code users._id} — 참가자 목록의 userId)
|
|
380
380
|
* @returns {Promise<Object>}
|
|
381
381
|
*/
|
|
382
382
|
async createOneToOneRoom(friendId) {
|
package/src/index.js
CHANGED
|
@@ -10,35 +10,27 @@
|
|
|
10
10
|
* 자세한 내용은 README 의 "프로덕션 인증 플로우" 섹션 참고.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
|
-
* // ===
|
|
13
|
+
* // === 시작하기 — 이메일/비밀번호 로그인 ===
|
|
14
14
|
* import TalkFlowClient from '@talkflow/sdk';
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* // 1단계: 로그인. 클라이언트 생성 «전» 에 부른다 — ck/projectId/JWT 를 한 번에 받는다.
|
|
17
|
+
* const { clientKey, projectId, accessToken } = await TalkFlowClient.loginUser({
|
|
18
|
+
* serverUrl: 'https://chat.apiorbit.net',
|
|
19
|
+
* email: 'me@example.com',
|
|
20
|
+
* password: '••••••••'
|
|
20
21
|
* });
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
* await client.connect();
|
|
24
|
-
* await client.chat.sendTextMessage('room-id', '안녕하세요!');
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* // === 프로덕션 — Client Key + Backend JWT 발급 ===
|
|
28
|
-
* // 1단계: 고객사 backend 에서 Server Key 로 JWT 발급
|
|
29
|
-
* // POST /api/v1/users/auth (X-API-KEY: SERVER_KEY)
|
|
30
|
-
* // → { accessToken }
|
|
31
|
-
*
|
|
32
|
-
* // 2단계: 브라우저 SDK 는 Client Key + JWT 로 초기화
|
|
23
|
+
* // 2단계: 받은 값 그대로 초기화
|
|
33
24
|
* const client = new TalkFlowClient({
|
|
34
|
-
* apiKey:
|
|
35
|
-
* projectId
|
|
36
|
-
* jwtToken:
|
|
25
|
+
* apiKey: clientKey, // ck- (브라우저 노출 안전)
|
|
26
|
+
* projectId,
|
|
27
|
+
* jwtToken: accessToken,
|
|
37
28
|
* env: 'production'
|
|
38
29
|
* });
|
|
39
30
|
*
|
|
40
31
|
* await client.connect();
|
|
41
32
|
* await client.chat.sendTextMessage('room-id', '안녕하세요!');
|
|
33
|
+
* await client.chat.sendTextMessage('room-id', '안녕하세요!');
|
|
42
34
|
*/
|
|
43
35
|
|
|
44
36
|
// 메인 클라이언트
|
package/src/talkflow/session.js
CHANGED
|
@@ -62,9 +62,9 @@ export function applySessionMethods(TalkFlowClient) {
|
|
|
62
62
|
|
|
63
63
|
if (!this.options.jwtToken) {
|
|
64
64
|
throw new Error(
|
|
65
|
-
'JWT token is required.
|
|
66
|
-
'
|
|
67
|
-
'
|
|
65
|
+
'JWT token is required. Sign in with TalkFlowClient.loginUser({ serverUrl, ' +
|
|
66
|
+
'email, password }) and pass the returned accessToken to the SDK via the ' +
|
|
67
|
+
'jwtToken option, setToken(), or connect(jwt). See README "로그인".'
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
package/types/index.d.ts
CHANGED
|
@@ -725,8 +725,6 @@ export interface ChatMessage {
|
|
|
725
725
|
nickName?: string;
|
|
726
726
|
/** 발신자 프로필 이미지 URL. */
|
|
727
727
|
profileUrl?: string | null;
|
|
728
|
-
/** 발신자의 프로젝트 스코프 사용자 ID. */
|
|
729
|
-
projectUserId?: string;
|
|
730
728
|
content: string | null;
|
|
731
729
|
chatMessageType: ChatMessageTypeValue;
|
|
732
730
|
chatType: string;
|
|
@@ -962,12 +960,102 @@ export interface DecisionResponse {
|
|
|
962
960
|
optionId: string;
|
|
963
961
|
}
|
|
964
962
|
|
|
963
|
+
/** 로그인한 회원. `userId` 는 메시지 발신자 식별과 같은 값이다. */
|
|
964
|
+
export interface LoginMember {
|
|
965
|
+
userId: string;
|
|
966
|
+
email?: string | null;
|
|
967
|
+
nickname?: string | null;
|
|
968
|
+
profileUrl?: string | null;
|
|
969
|
+
/** 회사 역할 — 클라이언트가 파트너 화면 노출을 결정한다. 인가 근거는 아니다(서버가 재확인). */
|
|
970
|
+
companyRole: 'PARTNER' | 'MEMBER';
|
|
971
|
+
preferredLanguage?: string | null;
|
|
972
|
+
/**
|
|
973
|
+
* 초기 비밀번호를 아직 안 바꿨는가 — `true` 면 **비밀번호 변경 화면으로 보내라**.
|
|
974
|
+
*
|
|
975
|
+
* 회원은 파트너가 정한 임시 비밀번호로 처음 들어오고, 파트너가 초기화하면 다시 이 상태가 된다.
|
|
976
|
+
* 로그인은 **성공** 한 것이다 — 실패로 다루면 사용자가 「비밀번호가 틀렸다」로 오해한다.
|
|
977
|
+
*/
|
|
978
|
+
mustChangePassword: boolean;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* `TalkFlowClient.loginUser` 응답.
|
|
983
|
+
*
|
|
984
|
+
* 회사 선택 단계가 없다 — 로그인 키가 전역 유일이라 이메일 하나로 회원과 회사가 함께 정해진다.
|
|
985
|
+
*/
|
|
986
|
+
export interface LoginResult {
|
|
987
|
+
accessToken: string;
|
|
988
|
+
tokenType: string;
|
|
989
|
+
expiresIn?: number;
|
|
990
|
+
projectId: string;
|
|
991
|
+
/** 회사의 활성 ck- 키. SDK 초기화의 `apiKey` 로 그대로 넣는다. */
|
|
992
|
+
clientKey: string;
|
|
993
|
+
user: LoginMember;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/** 회사 조직도의 회원 — 초대 UI 에 필요한 것만. */
|
|
997
|
+
export interface DirectoryMember {
|
|
998
|
+
userId: string;
|
|
999
|
+
name?: string | null;
|
|
1000
|
+
profileUrl?: string | null;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/** 조직도 노드. `parentId` 가 null 이면 최상위. */
|
|
1004
|
+
export interface DirectoryNode {
|
|
1005
|
+
orgNodeId: string;
|
|
1006
|
+
name: string;
|
|
1007
|
+
parentId?: string | null;
|
|
1008
|
+
sortOrder: number;
|
|
1009
|
+
/** 자손 포함 누적 인원 — 화면의 「개발팀 (2)」가 이 값. */
|
|
1010
|
+
memberCount: number;
|
|
1011
|
+
/** 이 노드 직속 인원 수. */
|
|
1012
|
+
directMemberCount: number;
|
|
1013
|
+
/** 이 노드 **직속** 회원. 누적 목록은 `children` 을 따라 모은다. */
|
|
1014
|
+
members: DirectoryMember[];
|
|
1015
|
+
children: DirectoryNode[];
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/** `getCompanyDirectory()` 응답. */
|
|
1019
|
+
export interface CompanyDirectory {
|
|
1020
|
+
tree: DirectoryNode[];
|
|
1021
|
+
/** 부서가 없는 회원 — 빠지면 초대 화면에서 그 사람을 찾을 수 없다. */
|
|
1022
|
+
unassignedMembers: DirectoryMember[];
|
|
1023
|
+
/** 활성 회원 총수(트리 + 미지정). */
|
|
1024
|
+
totalMemberCount: number;
|
|
1025
|
+
/** true 면 인원 **수** 는 정확하지만 **목록** 이 비어 있다 — 검색 기반 선택으로 넘어가야 한다. */
|
|
1026
|
+
membersOmitted: boolean;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/** 내 정보. 수정 응답에는 `accessToken` 이 함께 온다(name/profileUrl 이 토큰 claim). */
|
|
1030
|
+
export interface MyProfile {
|
|
1031
|
+
userId: string;
|
|
1032
|
+
email?: string | null;
|
|
1033
|
+
name?: string | null;
|
|
1034
|
+
phone?: string | null;
|
|
1035
|
+
profileUrl?: string | null;
|
|
1036
|
+
/** 회사 역할 — 방 역할(ParticipantResponse.role)과 다른 축이다. */
|
|
1037
|
+
companyRole: 'PARTNER' | 'MEMBER';
|
|
1038
|
+
orgNodeId?: string | null;
|
|
1039
|
+
orgName?: string | null;
|
|
1040
|
+
preferredLanguage?: string | null;
|
|
1041
|
+
projectId: string;
|
|
1042
|
+
joinedAt?: string | null;
|
|
1043
|
+
/**
|
|
1044
|
+
* 초기 비밀번호를 아직 안 바꿨는가 — `true` 면 비밀번호 변경을 요구해야 한다.
|
|
1045
|
+
*
|
|
1046
|
+
* 로그인 응답에도 같은 값이 있다. 여기에도 있는 이유: 새로고침·딥링크로 로그인 응답을 거치지
|
|
1047
|
+
* 않고 들어오는 화면에서 그 요구가 조용히 사라지지 않게 하려는 것이다.
|
|
1048
|
+
*/
|
|
1049
|
+
mustChangePassword: boolean;
|
|
1050
|
+
accessToken?: string;
|
|
1051
|
+
expiresIn?: number;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
965
1054
|
/** 채팅방 참가자. */
|
|
966
1055
|
export interface ParticipantResponse {
|
|
967
1056
|
userId: string;
|
|
968
1057
|
nickName?: string;
|
|
969
1058
|
profileUrl?: string | null;
|
|
970
|
-
projectUserId?: string;
|
|
971
1059
|
/**
|
|
972
1060
|
* 참가자 역할 — 서버 {@code ParticipantRole} enum 과 일치.
|
|
973
1061
|
* <ul>
|
|
@@ -2251,6 +2339,30 @@ export default class TalkFlowClient implements SdkEventEmitter<TalkFlowClientEve
|
|
|
2251
2339
|
removeAllListeners(event?: keyof TalkFlowClientEvents): void;
|
|
2252
2340
|
listenerCount(event: keyof TalkFlowClientEvents): number;
|
|
2253
2341
|
|
|
2342
|
+
// 회원 인증 · 내 정보
|
|
2343
|
+
/**
|
|
2344
|
+
* 회원 로그인 — 클라이언트 생성 **전에** 호출한다. Server Key 도 고객사 BFF 도 필요 없다.
|
|
2345
|
+
* 응답의 `clientKey`/`projectId`/`accessToken` 이 그대로 SDK 초기화 입력이다.
|
|
2346
|
+
* 회사 선택 단계가 없다 — 로그인 키가 전역 유일이다.
|
|
2347
|
+
*/
|
|
2348
|
+
static loginUser(options: {
|
|
2349
|
+
serverUrl: string;
|
|
2350
|
+
email: string;
|
|
2351
|
+
password: string;
|
|
2352
|
+
}): Promise<LoginResult>;
|
|
2353
|
+
|
|
2354
|
+
/** 회원 로그인 (인스턴스) — 재로그인·계정 전환용. 성공 시 토큰을 자동 설정한다. */
|
|
2355
|
+
loginUser(credentials: { email: string; password: string }): Promise<LoginResult>;
|
|
2356
|
+
|
|
2357
|
+
/** 내 정보 조회. */
|
|
2358
|
+
getMyProfile(): Promise<MyProfile>;
|
|
2359
|
+
|
|
2360
|
+
/** 내 정보 수정 — 응답의 새 토큰을 자동 채택한다(name/profileUrl 이 토큰 claim). */
|
|
2361
|
+
updateMyProfile(profile: { name?: string; phone?: string; profileUrl?: string }): Promise<MyProfile>;
|
|
2362
|
+
|
|
2363
|
+
/** 비밀번호 변경 — 현재 비밀번호 재확인. 토큰은 그대로 유효해 재로그인이 필요 없다. */
|
|
2364
|
+
changeMyPassword(params: { currentPassword: string; newPassword: string }): Promise<unknown>;
|
|
2365
|
+
|
|
2254
2366
|
// Connection lifecycle
|
|
2255
2367
|
connect(jwt?: string, options?: ConnectOptions): Promise<void>;
|
|
2256
2368
|
disconnect(): Promise<void>;
|