connectbase-client 3.23.0 → 3.25.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 +52 -575
- package/dist/cli.js +353 -1748
- package/dist/connect-base.umd.js +2 -4
- package/dist/index.d.mts +347 -3234
- package/dist/index.d.ts +347 -3234
- package/dist/index.js +1057 -4131
- package/dist/index.mjs +1054 -4123
- package/package.json +7 -19
- package/CHANGELOG.md +0 -1884
- package/LICENSE +0 -21
- package/MIGRATION-v2.md +0 -149
package/dist/index.d.ts
CHANGED
|
@@ -1,149 +1,24 @@
|
|
|
1
|
-
interface ApiErrorDetail {
|
|
2
|
-
code: string;
|
|
3
|
-
message: string;
|
|
4
|
-
details?: unknown;
|
|
5
|
-
}
|
|
6
1
|
declare class ApiError extends Error {
|
|
7
2
|
statusCode: number;
|
|
8
|
-
|
|
9
|
-
details: unknown | undefined;
|
|
10
|
-
constructor(statusCode: number, message: string, code?: string, details?: unknown);
|
|
3
|
+
constructor(statusCode: number, message: string);
|
|
11
4
|
}
|
|
12
5
|
declare class AuthError extends Error {
|
|
13
6
|
constructor(message: string);
|
|
14
7
|
}
|
|
15
|
-
/**
|
|
16
|
-
* GameError 는 game-server 가 surface 한 `error` 메시지 (createRoom/joinRoom/sendAction
|
|
17
|
-
* 응답 또는 broadcastScriptError) 를 client 측에서 일관된 형태로 다루기 위한 예외 클래스.
|
|
18
|
-
*
|
|
19
|
-
* 기존엔 모든 reject 가 `new Error(message)` 였어서 `code`/`phase`/`feature` 같은
|
|
20
|
-
* 분류 메타가 손실되어 SDK 사용자가 onError UI 분기를 만들 수 없었다 (NJB 사례,
|
|
21
|
-
* platform-issue 019e21dd / 2026-05-13).
|
|
22
|
-
*
|
|
23
|
-
* 사용 패턴:
|
|
24
|
-
* ```ts
|
|
25
|
-
* try {
|
|
26
|
-
* await room.createRoom({ scriptName: 'my-script' })
|
|
27
|
-
* } catch (e) {
|
|
28
|
-
* if (e instanceof GameError && e.code === 'SCRIPT_NOT_FOUND') {
|
|
29
|
-
* console.error('script missing — available:', e.available)
|
|
30
|
-
* }
|
|
31
|
-
* }
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* onError 콜백도 동일하게 GameError 인스턴스로 surface 된다.
|
|
35
|
-
*/
|
|
36
|
-
declare class GameError extends Error {
|
|
37
|
-
/** server 가 분류한 에러 코드. literal 비교용은 GameErrorCode 참조. */
|
|
38
|
-
code: string;
|
|
39
|
-
/** Lua hook 단계 — 'onJoin'|'onLeave'|'onTick'|'onAction'. 비-lua 에러는 undefined. */
|
|
40
|
-
phase?: string;
|
|
41
|
-
/** FEATURE_DISABLED 시 비활성 feature 이름. */
|
|
42
|
-
feature?: string;
|
|
43
|
-
/** 영향받은 room id. */
|
|
44
|
-
roomId?: string;
|
|
45
|
-
/** `<appID>:<scriptName>` 형식의 attached script id. */
|
|
46
|
-
scriptId?: string;
|
|
47
|
-
/** broadcast 형태의 onAction 에러일 때, 액션을 일으킨 client (본인 아님 확인용). */
|
|
48
|
-
originClientId?: string;
|
|
49
|
-
/** SCRIPT_NOT_FOUND 응답 시 요청했던 scriptName. */
|
|
50
|
-
requested?: string;
|
|
51
|
-
/** SCRIPT_NOT_FOUND 응답 시 active 상태인 script 이름 목록. */
|
|
52
|
-
available?: string[];
|
|
53
|
-
constructor(init: {
|
|
54
|
-
code?: string;
|
|
55
|
-
message?: string;
|
|
56
|
-
phase?: string;
|
|
57
|
-
feature?: string;
|
|
58
|
-
roomId?: string;
|
|
59
|
-
scriptId?: string;
|
|
60
|
-
originClientId?: string;
|
|
61
|
-
requested?: string;
|
|
62
|
-
available?: string[];
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
interface AbortOptions {
|
|
67
|
-
timeout?: number;
|
|
68
|
-
signal?: AbortSignal;
|
|
69
|
-
}
|
|
70
8
|
|
|
71
|
-
/**
|
|
72
|
-
* Recent API calls breadcrumb buffer — SDK 디버깅 / platform issue 발행 시 자동 첨부.
|
|
73
|
-
*
|
|
74
|
-
* **저장 정책 (PII 보호):**
|
|
75
|
-
* - method, path (query string strip), status, duration_ms, timestamp 만 저장
|
|
76
|
-
* - body / response body / 인증 토큰 미저장
|
|
77
|
-
* - URL 내 secret-like 패턴 (key=, token=, password=) 자동 redact
|
|
78
|
-
* - `/v1/auth/*`, `/v1/oauth/token` 등 민감 endpoint 는 path 만 (쿼리 strip)
|
|
79
|
-
*/
|
|
80
|
-
interface RecentApiCall {
|
|
81
|
-
method: string;
|
|
82
|
-
path: string;
|
|
83
|
-
status: number;
|
|
84
|
-
duration_ms: number;
|
|
85
|
-
timestamp: string;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
type TokenPersistence = 'localStorage' | 'sessionStorage' | 'none';
|
|
89
9
|
interface HttpClientConfig {
|
|
90
10
|
baseUrl: string;
|
|
91
|
-
|
|
92
|
-
* Public Key (cb_pk_* 형식). 콘솔 → 설정 → API 에서 발급.
|
|
93
|
-
* 브라우저/클라이언트에서 사용 (Row Level Security 적용).
|
|
94
|
-
*/
|
|
95
|
-
publicKey?: string;
|
|
96
|
-
/**
|
|
97
|
-
* Secret Key (cb_sk_* 형식). 사용자 프로필에서 발급.
|
|
98
|
-
* 서버 환경에서만 사용 (전체 권한, 절대 노출 금지).
|
|
99
|
-
*/
|
|
100
|
-
secretKey?: string;
|
|
11
|
+
apiKey?: string;
|
|
101
12
|
accessToken?: string;
|
|
102
13
|
refreshToken?: string;
|
|
103
|
-
/**
|
|
104
|
-
* 토큰 저장 방식. **기본값은 'none' (메모리 저장)**.
|
|
105
|
-
* XSS 취약점이 하나라도 있을 경우 영구 저장은 즉시 전 세션 탈취로 이어지므로,
|
|
106
|
-
* 영구 저장 옵션은 위험을 이해하고 명시적으로 선택한 경우에만 사용한다.
|
|
107
|
-
*
|
|
108
|
-
* - 'none' (권장·기본값): access token 만 메모리 저장. refresh token 은 서버가 발급한
|
|
109
|
-
* HttpOnly cookie 로만 보관되어 JS 가 접근할 수 없다 (XSS 시 탈취 불가). 새로고침 후에는
|
|
110
|
-
* `autoRestoreSession`(기본 true) 으로 cookie 만으로 자동 복구된다.
|
|
111
|
-
* - 'sessionStorage': 탭 종료 시 삭제. JS 접근 가능 → XSS 로 탭 세션 탈취 가능
|
|
112
|
-
* - 'localStorage': 브라우저 종료 후에도 유지. JS 접근 가능 → XSS 로 영구 탈취 가능
|
|
113
|
-
*/
|
|
114
|
-
persistence?: TokenPersistence;
|
|
115
|
-
/**
|
|
116
|
-
* 새로고침/탭 재개 시 HttpOnly cookie 로부터 access token 을 자동 복구할지 여부.
|
|
117
|
-
* 기본값은 브라우저 환경에서 true. 비-브라우저(Node.js, RN) 에서는 무시된다.
|
|
118
|
-
*
|
|
119
|
-
* cookie 가 없는 경우(미로그인) 조용히 실패하며 콘솔 에러를 발생시키지 않는다.
|
|
120
|
-
*/
|
|
121
|
-
autoRestoreSession?: boolean;
|
|
122
|
-
/**
|
|
123
|
-
* 요청별 기본 타임아웃(ms). 개별 호출의 `timeout` 이 우선.
|
|
124
|
-
* 기본값 30000ms. 0 또는 음수 지정 시 타임아웃 비활성화.
|
|
125
|
-
*/
|
|
126
|
-
requestTimeoutMs?: number;
|
|
127
|
-
/**
|
|
128
|
-
* 전역 에러 관찰자. 모든 ApiError/AuthError 발생 시 호출된다.
|
|
129
|
-
* 운영 관측성(Sentry/Datadog/자체 엔드포인트)과 연결하기 위한 훅.
|
|
130
|
-
*/
|
|
131
|
-
onError?: (error: ApiError | AuthError) => void;
|
|
132
14
|
onTokenRefresh?: (tokens: {
|
|
133
15
|
accessToken: string;
|
|
134
16
|
refreshToken: string;
|
|
135
17
|
}) => void;
|
|
136
18
|
onAuthError?: (error: AuthError) => void;
|
|
137
19
|
onTokenExpired?: () => void;
|
|
138
|
-
/**
|
|
139
|
-
* `/v1/auth/re-issue` 의 일시적 실패(5xx, 네트워크 오류, abort) 발생 시 호출.
|
|
140
|
-
* 이 경우 토큰은 폐기되지 않으며 `onTokenExpired` 도 호출되지 않는다 — 다음 호출에서
|
|
141
|
-
* backoff 만료 후 자동 재시도. 사용자에게 "연결이 잠시 불안정합니다" 같은 비파괴적 알림을
|
|
142
|
-
* 표시할 때 사용. `onAuthError` 도 함께 호출되므로 둘을 동시에 wiring 하면 중복 처리에 주의.
|
|
143
|
-
*/
|
|
144
|
-
onTransientRefreshFailure?: (error: AuthError) => void;
|
|
145
20
|
}
|
|
146
|
-
interface RequestConfig
|
|
21
|
+
interface RequestConfig {
|
|
147
22
|
skipAuth?: boolean;
|
|
148
23
|
headers?: Record<string, string>;
|
|
149
24
|
}
|
|
@@ -151,574 +26,35 @@ declare class HttpClient {
|
|
|
151
26
|
private config;
|
|
152
27
|
private isRefreshing;
|
|
153
28
|
private refreshPromise;
|
|
154
|
-
private storageKey;
|
|
155
|
-
private refreshFailureCount;
|
|
156
|
-
private refreshLockedUntil;
|
|
157
|
-
/**
|
|
158
|
-
* 최근 API 호출 breadcrumb (PII strip 후 저장). platform_issue 발행 시 자동 첨부 가능.
|
|
159
|
-
* `client.support.getRecentCalls()` 로 외부 노출.
|
|
160
|
-
*/
|
|
161
|
-
private recentCalls;
|
|
162
|
-
/**
|
|
163
|
-
* 부팅 시 fire-and-forget 으로 시작한 cookie 기반 복구 promise. `prepareHeaders` 가
|
|
164
|
-
* 인증 호출을 보내기 직전에 이 promise 를 await 해, 페이지 진입 직후 첫 API 호출이
|
|
165
|
-
* 메모리 토큰 빈 상태로 401 받는 race 를 막는다 (platform-issue 019e638d, 2026-05-26).
|
|
166
|
-
* 한 번 settle 되면 그 결과(메모리 적재 또는 미로그인)가 항상 반영되어 있다.
|
|
167
|
-
*/
|
|
168
|
-
private bootRestorePromise;
|
|
169
29
|
constructor(config: HttpClientConfig);
|
|
170
|
-
/**
|
|
171
|
-
* 페이지 진입 시 fire-and-forget 으로 시작된 cookie 복구 promise 를 SDK 가 등록한다.
|
|
172
|
-
* 같은 promise 가 `prepareHeaders` 에서 await 되어, 첫 인증 호출이 cookie 복구
|
|
173
|
-
* 완료 후 발화한다.
|
|
174
|
-
*/
|
|
175
|
-
setBootRestorePromise(p: Promise<boolean>): void;
|
|
176
|
-
/** 최근 호출 ring buffer 스냅샷 (시간순). */
|
|
177
|
-
getRecentCalls(): RecentApiCall[];
|
|
178
|
-
/** 최근 호출 buffer clear (테스트/프라이버시 처리). */
|
|
179
|
-
clearRecentCalls(): void;
|
|
180
|
-
private warnIfUnsafePersistence;
|
|
181
30
|
updateConfig(config: Partial<HttpClientConfig>): void;
|
|
182
31
|
setTokens(accessToken: string, refreshToken: string): void;
|
|
183
32
|
clearTokens(): void;
|
|
184
33
|
/**
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* 배경: 콜백 흐름에서 서버가 redirect 응답에 Set-Cookie 를 함께 발급하지만, 일부 deployment /
|
|
188
|
-
* 브라우저 정책 / 사용자 설정 (3rd-party cookie 차단 등) 환경에서 이 Set-Cookie 가 브라우저에
|
|
189
|
-
* 저장되지 않는다. `persistence='none'` 모드에서는 토큰이 메모리에만 있고 cookie 가 없는 상태로
|
|
190
|
-
* 페이지 새로고침이 발생하면 `/v1/auth/re-issue` 가 401 으로 떨어져 강제 로그아웃되는 회귀가
|
|
191
|
-
* 있다 (platform-issue 019e3960, 2026-05-18).
|
|
192
|
-
*
|
|
193
|
-
* 이 메서드는 메모리의 refresh token 으로 한 번 `/v1/auth/re-issue` 를 호출해 서버가 cookie 를
|
|
194
|
-
* 명시적으로 발급하도록 유도한다. 백엔드는 Bearer + `X-Public-Key` 조합을 SDK 호출 신호로
|
|
195
|
-
* 인식해 응답에 `cb_member_refresh_token` cookie 를 함께 내려준다.
|
|
196
|
-
*
|
|
197
|
-
* persistence='localStorage' / 'sessionStorage' 모드는 새로고침 후에도 메모리 복구가 가능하므로
|
|
198
|
-
* 호출하지 않는다 (rotation 만 일어나 비용만 증가). 비-브라우저 환경에서도 cookie 자체가 없으므로
|
|
199
|
-
* 호출하지 않는다.
|
|
200
|
-
*/
|
|
201
|
-
bootstrapRefreshCookie(): Promise<void>;
|
|
202
|
-
private get persistence();
|
|
203
|
-
private getStorage;
|
|
204
|
-
/**
|
|
205
|
-
* AuthAPI 등 내부 사용자가 "현재 persistence 설정된 스토리지"를 확인할 수 있도록 노출.
|
|
206
|
-
* persistence='none' 이면 null. XSS 완화 기본값을 공유하기 위함.
|
|
207
|
-
*/
|
|
208
|
-
getPersistenceStorage(): Storage | null;
|
|
209
|
-
private buildStorageKey;
|
|
210
|
-
private persistTokens;
|
|
211
|
-
private restoreTokens;
|
|
212
|
-
private removePersistedTokens;
|
|
213
|
-
/**
|
|
214
|
-
* Public Key 가 설정되어 있는지 확인
|
|
215
|
-
*/
|
|
216
|
-
hasPublicKey(): boolean;
|
|
217
|
-
/**
|
|
218
|
-
* Public Key 반환
|
|
34
|
+
* API Key가 설정되어 있는지 확인
|
|
219
35
|
*/
|
|
220
|
-
|
|
36
|
+
hasApiKey(): boolean;
|
|
221
37
|
/**
|
|
222
|
-
*
|
|
38
|
+
* API Key 반환
|
|
223
39
|
*/
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Secret Key 반환
|
|
227
|
-
*/
|
|
228
|
-
getSecretKey(): string | undefined;
|
|
229
|
-
/**
|
|
230
|
-
* 현재 설정된 자격증명 반환.
|
|
231
|
-
*
|
|
232
|
-
* publicKey 가 있으면 그걸 반환한다 (X-Public-Key 헤더 = 앱 식별용 = cb_pk_*).
|
|
233
|
-
* publicKey 가 없고 secretKey 만 있는 경우는 secretKey 로 폴백 — 단, 서버는
|
|
234
|
-
* cb_sk_ 가 X-Public-Key 에 실리면 거부하므로 의도된 401 이 나간다(앱 식별 불가).
|
|
235
|
-
*
|
|
236
|
-
* secretKey 의 admin 권한은 별도로 Authorization: Bearer 로 보낸다. 그 처리는
|
|
237
|
-
* prepareHeaders 안에서 publicKey + secretKey 가 함께 있을 때 수행한다.
|
|
238
|
-
*/
|
|
239
|
-
getCredential(): string | undefined;
|
|
40
|
+
getApiKey(): string | undefined;
|
|
240
41
|
/**
|
|
241
42
|
* Access Token 반환
|
|
242
43
|
*/
|
|
243
44
|
getAccessToken(): string | undefined;
|
|
244
|
-
/**
|
|
245
|
-
* JWT(Access Token) 가 설정되어 있는지 확인
|
|
246
|
-
*/
|
|
247
|
-
hasJWT(): boolean;
|
|
248
45
|
/**
|
|
249
46
|
* Base URL 반환
|
|
250
47
|
*/
|
|
251
48
|
getBaseUrl(): string;
|
|
252
49
|
private refreshAccessToken;
|
|
253
|
-
/**
|
|
254
|
-
* 새로고침/탭 재개 시 HttpOnly cookie 만으로 access token 을 복구한다.
|
|
255
|
-
*
|
|
256
|
-
* 동작:
|
|
257
|
-
* - 메모리에 access token 이 이미 있으면 그대로 반환 (true).
|
|
258
|
-
* - 없으면 `/v1/auth/re-issue` 를 cookie 만으로 호출. cookie 가 있으면 access token 회복.
|
|
259
|
-
* - cookie 가 없거나(미로그인) 만료된 경우 조용히 false 반환 (콘솔 에러 없음).
|
|
260
|
-
*
|
|
261
|
-
* 비-브라우저 환경에서는 cookie 흐름이 없으므로 즉시 false 반환.
|
|
262
|
-
*/
|
|
263
|
-
tryRestoreSessionFromCookie(): Promise<boolean>;
|
|
264
|
-
private emitError;
|
|
265
50
|
private isTokenExpired;
|
|
266
51
|
private prepareHeaders;
|
|
267
52
|
private handleResponse;
|
|
268
|
-
/**
|
|
269
|
-
* AbortController 를 관리하며 fetch 호출을 실행. 타임아웃/외부 signal 병합.
|
|
270
|
-
*
|
|
271
|
-
* 401 자동 복구: 인증 호출이 401 을 받으면 cookie 기반 복구를 *한 번* 시도하고 retry 한다.
|
|
272
|
-
* 메모리 토큰이 만료/누락 + cookie 는 살아 있는 경우를 자동으로 회복시켜,
|
|
273
|
-
* 페이지 진입 직후 race 로 401 을 받은 첫 호출이 사용자 흐름을 차단하지 않게 한다
|
|
274
|
-
* (platform-issue 019e638d, 2026-05-26). retry 는 1회 한정 — 무한 루프 차단.
|
|
275
|
-
*/
|
|
276
|
-
private doFetch;
|
|
277
|
-
private tryFetchOnce;
|
|
278
53
|
get<T>(url: string, config?: RequestConfig): Promise<T>;
|
|
279
54
|
post<T>(url: string, data?: unknown, config?: RequestConfig): Promise<T>;
|
|
280
55
|
put<T>(url: string, data: unknown, config?: RequestConfig): Promise<T>;
|
|
281
56
|
patch<T>(url: string, data: unknown, config?: RequestConfig): Promise<T>;
|
|
282
57
|
delete<T>(url: string, config?: RequestConfig): Promise<T>;
|
|
283
|
-
/**
|
|
284
|
-
* Raw fetch 요청 (SSE 스트리밍 등에 사용)
|
|
285
|
-
* 인증 헤더가 자동으로 추가됩니다. timeout 은 호출자가 직접 signal 로 관리해야 합니다
|
|
286
|
-
* (스트리밍 특성상 전역 timeout 을 강제하지 않음).
|
|
287
|
-
*/
|
|
288
|
-
fetchRaw(url: string, init?: RequestInit): Promise<Response>;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
interface AnalyticsConfig {
|
|
292
|
-
/** 자동 페이지뷰 추적 @default true */
|
|
293
|
-
trackPageViews?: boolean;
|
|
294
|
-
/** 커스텀 이벤트 활성화 @default true */
|
|
295
|
-
trackEvents?: boolean;
|
|
296
|
-
/** 세션 + heartbeat @default true */
|
|
297
|
-
trackSessions?: boolean;
|
|
298
|
-
/** 히트맵 (opt-in) @default false */
|
|
299
|
-
heatmap?: boolean;
|
|
300
|
-
/** 세션 녹화 (opt-in) @default false */
|
|
301
|
-
recording?: boolean;
|
|
302
|
-
/** 배치 크기 @default 10 */
|
|
303
|
-
batchSize?: number;
|
|
304
|
-
/** 배치 전송 간격 (ms) @default 5000 */
|
|
305
|
-
flushInterval?: number;
|
|
306
|
-
/** DNT 헤더 존중 @default true */
|
|
307
|
-
respectDoNotTrack?: boolean;
|
|
308
|
-
/** 디버그 모드 @default false */
|
|
309
|
-
debug?: boolean;
|
|
310
|
-
}
|
|
311
|
-
interface ConsentOptions {
|
|
312
|
-
analytics?: boolean;
|
|
313
|
-
heatmap?: boolean;
|
|
314
|
-
recording?: boolean;
|
|
315
|
-
}
|
|
316
|
-
interface AnalyticsEvent {
|
|
317
|
-
name: string;
|
|
318
|
-
properties?: Record<string, unknown>;
|
|
319
|
-
timestamp?: number;
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* 인기 페이지 목록 응답.
|
|
323
|
-
*
|
|
324
|
-
* 백엔드 `dto.PopularPagesResponse` 와 1:1 매핑.
|
|
325
|
-
*/
|
|
326
|
-
interface PopularPagesResponse {
|
|
327
|
-
pages: Array<{
|
|
328
|
-
page_path: string;
|
|
329
|
-
page_views: number;
|
|
330
|
-
}>;
|
|
331
|
-
start_date: number;
|
|
332
|
-
end_date: number;
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* 방문자 목록 응답.
|
|
336
|
-
*
|
|
337
|
-
* 백엔드 `dto.VisitorListResponse` 와 1:1 매핑. `app_member_id` 는 게스트 방문자에는
|
|
338
|
-
* 없을 수 있다.
|
|
339
|
-
*/
|
|
340
|
-
interface VisitorListResponse {
|
|
341
|
-
visitors: Array<{
|
|
342
|
-
id: string;
|
|
343
|
-
visitor_uid: string;
|
|
344
|
-
app_member_id?: string;
|
|
345
|
-
total_visits: number;
|
|
346
|
-
total_page_views: number;
|
|
347
|
-
referrer?: string;
|
|
348
|
-
last_ip?: string;
|
|
349
|
-
country?: string;
|
|
350
|
-
is_bot: boolean;
|
|
351
|
-
first_visit_at: string;
|
|
352
|
-
last_visit_at: string;
|
|
353
|
-
}>;
|
|
354
|
-
total: number;
|
|
355
|
-
limit: number;
|
|
356
|
-
offset: number;
|
|
357
|
-
has_more: boolean;
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* 페이지 전환 플로우(Sankey) 응답.
|
|
361
|
-
*
|
|
362
|
-
* 백엔드 `dto.NavigationFlowResponse` 와 1:1 매핑. `nodes` 는 페이지, `links` 는 전환.
|
|
363
|
-
*/
|
|
364
|
-
interface NavigationFlowResponse {
|
|
365
|
-
nodes: Array<{
|
|
366
|
-
id: string;
|
|
367
|
-
label: string;
|
|
368
|
-
value: number;
|
|
369
|
-
}>;
|
|
370
|
-
links: Array<{
|
|
371
|
-
source: string;
|
|
372
|
-
target: string;
|
|
373
|
-
value: number;
|
|
374
|
-
}>;
|
|
375
|
-
}
|
|
376
|
-
/**
|
|
377
|
-
* 조회 메서드 공통 옵션.
|
|
378
|
-
*
|
|
379
|
-
* `start_date` / `end_date` 는 백엔드가 정수형 epoch-day 또는 yyyymmdd 로 다루는 값
|
|
380
|
-
* (서비스 메서드 시그니처 기준 int). 0 또는 미지정 시 기본 기간을 사용.
|
|
381
|
-
*/
|
|
382
|
-
interface AnalyticsRangeOptions {
|
|
383
|
-
start_date?: number;
|
|
384
|
-
end_date?: number;
|
|
385
|
-
limit?: number;
|
|
386
|
-
}
|
|
387
|
-
interface VisitorListOptions {
|
|
388
|
-
limit?: number;
|
|
389
|
-
offset?: number;
|
|
390
|
-
/**
|
|
391
|
-
* 백엔드가 인식하는 정렬 키 — 외 값은 silent 로 default(`last_visit`) 처리됩니다.
|
|
392
|
-
*
|
|
393
|
-
* 1.12.0 에서 백엔드 실제 동작에 맞춰 enum 정정 (1.10/1.11 의 `total_visits`/
|
|
394
|
-
* `total_page_views` 는 백엔드에서 인식되지 않아 항상 default 분기였음).
|
|
395
|
-
*/
|
|
396
|
-
sort_by?: 'last_visit' | 'visits' | 'page_views' | 'first_visit';
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* 멤버별 합산 방문자 그룹 항목.
|
|
400
|
-
*
|
|
401
|
-
* 한 명의 회원이 여러 디바이스/브라우저로 접속했을 때 visitor row 들을 합쳐 단일 row.
|
|
402
|
-
* 익명 visitor 는 `app_member_id == undefined` 로 단일 row 그대로 노출되며 `visitor_count == 1`.
|
|
403
|
-
*
|
|
404
|
-
* `visitor_count` 는 "디바이스 수" 가 아닌 **"추적 브라우저 인스턴스 수"** 를 의미합니다.
|
|
405
|
-
* 같은 디바이스에서 시크릿모드 + 일반모드는 visitor 2 = visitor_count 2 로 카운트됩니다.
|
|
406
|
-
*/
|
|
407
|
-
interface VisitorGroupItem {
|
|
408
|
-
app_member_id?: string;
|
|
409
|
-
/** 익명 visitor row 의 경우 단일 visitor_uid. 회원 그룹은 visitor_uids 참조. */
|
|
410
|
-
visitor_uid?: string;
|
|
411
|
-
/** 회원 그룹에 속한 visitor_uid 목록. 익명 row 는 undefined. */
|
|
412
|
-
visitor_uids?: string[];
|
|
413
|
-
visitor_count: number;
|
|
414
|
-
total_visits: number;
|
|
415
|
-
total_page_views: number;
|
|
416
|
-
first_visit_at: string;
|
|
417
|
-
last_visit_at: string;
|
|
418
|
-
country?: string;
|
|
419
|
-
is_bot: boolean;
|
|
420
|
-
}
|
|
421
|
-
interface VisitorGroupListResponse {
|
|
422
|
-
groups: VisitorGroupItem[];
|
|
423
|
-
total: number;
|
|
424
|
-
limit: number;
|
|
425
|
-
offset: number;
|
|
426
|
-
has_more: boolean;
|
|
427
|
-
}
|
|
428
|
-
interface VisitorByMemberResponse {
|
|
429
|
-
app_member_id: string;
|
|
430
|
-
visitor_uids: string[];
|
|
431
|
-
visitor_count: number;
|
|
432
|
-
total_visits: number;
|
|
433
|
-
total_page_views: number;
|
|
434
|
-
first_visit_at: string;
|
|
435
|
-
last_visit_at: string;
|
|
436
|
-
country?: string;
|
|
437
|
-
is_bot: boolean;
|
|
438
|
-
}
|
|
439
|
-
interface MergeVisitorsRequest {
|
|
440
|
-
source_visitor_uid: string;
|
|
441
|
-
/** target_visitor_uid 또는 target_member_id 중 하나는 필수. */
|
|
442
|
-
target_visitor_uid?: string;
|
|
443
|
-
target_member_id?: string;
|
|
444
|
-
}
|
|
445
|
-
interface MergeVisitorsResponse {
|
|
446
|
-
success: boolean;
|
|
447
|
-
target_visitor_id: string;
|
|
448
|
-
moved_records: number;
|
|
449
|
-
message?: string;
|
|
450
|
-
}
|
|
451
|
-
declare class SessionManager {
|
|
452
|
-
private _sessionId;
|
|
453
|
-
private _visitorUid;
|
|
454
|
-
private _lastActivity;
|
|
455
|
-
private _isNewSession;
|
|
456
|
-
get sessionId(): string;
|
|
457
|
-
get visitorUid(): string;
|
|
458
|
-
get isNewSession(): boolean;
|
|
459
|
-
/** 활동 기록 — 세션 타임아웃 리셋 */
|
|
460
|
-
touch(): void;
|
|
461
|
-
/** 세션 강제 리셋 */
|
|
462
|
-
reset(): void;
|
|
463
|
-
/**
|
|
464
|
-
* visitor_uid 를 새로 발급하고 세션도 함께 초기화.
|
|
465
|
-
*
|
|
466
|
-
* 사용 시점:
|
|
467
|
-
* - 사용자 로그아웃 (이전 사용자 활동이 다음 사용자에 attribution 되는 것 방지)
|
|
468
|
-
* - 다른 사용자 로그인 감지 (link-member 가 `VISITOR_LINKED_TO_OTHER_MEMBER` 응답)
|
|
469
|
-
*
|
|
470
|
-
* localStorage 의 `__cb_visitor_uid` 가 새 UUID 로 교체되며 sessionStorage 의
|
|
471
|
-
* 세션 키도 같이 비워진다. 이후의 모든 batch 는 새 visitor 로 기록되어 멤버 간
|
|
472
|
-
* 데이터 오염이 차단된다.
|
|
473
|
-
*/
|
|
474
|
-
regenerateVisitorUid(): string;
|
|
475
|
-
private ensureSession;
|
|
476
|
-
private loadOrCreateVisitorUid;
|
|
477
|
-
}
|
|
478
|
-
declare class AnalyticsAPI {
|
|
479
|
-
private http;
|
|
480
|
-
private config;
|
|
481
|
-
private consent;
|
|
482
|
-
private session;
|
|
483
|
-
private storageWebId;
|
|
484
|
-
private memberId;
|
|
485
|
-
private eventQueue;
|
|
486
|
-
private batchTimer;
|
|
487
|
-
private isInitialized;
|
|
488
|
-
private heartbeatTimer;
|
|
489
|
-
private visibilityHandler;
|
|
490
|
-
private unloadHeartbeatHandler;
|
|
491
|
-
private popstateHandler;
|
|
492
|
-
private beforeUnloadHandler;
|
|
493
|
-
private origPushState;
|
|
494
|
-
private origReplaceState;
|
|
495
|
-
private heatmapClickHandler;
|
|
496
|
-
private heatmapScrollHandler;
|
|
497
|
-
private utm;
|
|
498
|
-
constructor(http: HttpClient);
|
|
499
|
-
/**
|
|
500
|
-
* Analytics 초기화
|
|
501
|
-
* @param storageWebId 웹 스토리지 ID
|
|
502
|
-
* @param config 설정 (선택)
|
|
503
|
-
*/
|
|
504
|
-
init(storageWebId: string, config?: AnalyticsConfig): void;
|
|
505
|
-
/** Analytics 정리 */
|
|
506
|
-
destroy(): void;
|
|
507
|
-
/**
|
|
508
|
-
* 동의 설정 변경
|
|
509
|
-
*/
|
|
510
|
-
setConsent(consent: ConsentOptions): void;
|
|
511
|
-
/** 현재 동의 상태 조회 */
|
|
512
|
-
getConsent(): ConsentOptions;
|
|
513
|
-
/**
|
|
514
|
-
* 페이지뷰 수동 추적
|
|
515
|
-
*/
|
|
516
|
-
trackPageView(path?: string): void;
|
|
517
|
-
/**
|
|
518
|
-
* 커스텀 이벤트 추적
|
|
519
|
-
*/
|
|
520
|
-
trackEvent(name: string, properties?: Record<string, unknown>): void;
|
|
521
|
-
/**
|
|
522
|
-
* 사용자 식별 (로그인 직후 호출).
|
|
523
|
-
*
|
|
524
|
-
* 이후 모든 방문 배치에 `app_member_id` 가 첨부되어 새 활동은 회원으로 기록됩니다.
|
|
525
|
-
* 추가로 **현재 visitor_uid 의 기존 익명 활동을 즉시 회원에게 backfill** 하기 위해
|
|
526
|
-
* 백엔드 `link-member` 엔드포인트를 한 번 호출합니다 (1.11.0+). 호출 실패는
|
|
527
|
-
* silent — 다음 batch 가 닿을 때 백엔드 자동 매핑이 동일하게 처리하므로 자가 복구.
|
|
528
|
-
*
|
|
529
|
-
* **사용자 전환 자동 처리 (1.13.0+)**: 동일 브라우저에서 다른 사용자가 로그인해
|
|
530
|
-
* 백엔드가 `VISITOR_LINKED_TO_OTHER_MEMBER` 응답을 보내면, 큐를 비우고
|
|
531
|
-
* `visitor_uid` 를 새로 발급한 뒤 link-member 를 한 번 더 호출해 새 visitor 가
|
|
532
|
-
* 즉시 회원으로 기록되도록 자가 복구한다.
|
|
533
|
-
*
|
|
534
|
-
* 산업 표준(GA4 User-ID, Mixpanel/PostHog `identify`) 과 동작 정합.
|
|
535
|
-
*
|
|
536
|
-
* @example
|
|
537
|
-
* ```ts
|
|
538
|
-
* // 로그인 성공 직후
|
|
539
|
-
* const member = await cb.auth.signInMember({ login_id, password })
|
|
540
|
-
* cb.analytics.identify(member.member_id)
|
|
541
|
-
* ```
|
|
542
|
-
*/
|
|
543
|
-
identify(memberId: string): void;
|
|
544
|
-
/**
|
|
545
|
-
* 로그아웃 / 사용자 전환 시 호출. 익명 상태로 복귀하면서 visitor_uid 를 새로
|
|
546
|
-
* 발급해 다음 사용자의 활동이 이전 사용자에게 attribution 되는 데이터 오염을 차단.
|
|
547
|
-
*
|
|
548
|
-
* 동작:
|
|
549
|
-
* 1. memberId 를 null 로 설정 (이후 batch 는 익명으로 기록)
|
|
550
|
-
* 2. 큐에 쌓인 미전송 이벤트 폐기 (이전 visitor 로 가는 것을 막기 위함)
|
|
551
|
-
* 3. localStorage `__cb_visitor_uid` 새 UUID 로 교체 + sessionStorage 세션 키 정리
|
|
552
|
-
* 4. heatmap 큐도 함께 비움
|
|
553
|
-
*
|
|
554
|
-
* @example
|
|
555
|
-
* ```ts
|
|
556
|
-
* // 로그아웃 핸들러
|
|
557
|
-
* await cb.auth.signOut()
|
|
558
|
-
* cb.analytics.reset()
|
|
559
|
-
* ```
|
|
560
|
-
*/
|
|
561
|
-
reset(): void;
|
|
562
|
-
/**
|
|
563
|
-
* 방문자 트래커에 현재 회원 ID 설정 (로그인/게스트 가입 시 호출).
|
|
564
|
-
*
|
|
565
|
-
* `identify()` 와 달리 즉시 backfill 호출은 하지 않습니다 — 단순히 이후 batch 의
|
|
566
|
-
* `app_member_id` 값만 갱신. null 을 넘기면 익명 상태로 복귀 (로그아웃 시에는
|
|
567
|
-
* 데이터 오염 방지를 위해 `reset()` 를 권장).
|
|
568
|
-
*/
|
|
569
|
-
setMemberId(memberId: string | null): void;
|
|
570
|
-
/**
|
|
571
|
-
* 백엔드 link-member 엔드포인트 한 번 호출 — 즉시 backfill 트리거.
|
|
572
|
-
*
|
|
573
|
-
* - 첫 페이지뷰가 아직 백엔드에 닿기 전이면 visitor 가 없어 404. 무시 — 다음 batch 가
|
|
574
|
-
* 가면 백엔드 BatchRecordVisit 가 자동 LinkMember 를 호출.
|
|
575
|
-
* - 다른 멤버에 이미 연결된 visitor 인 경우 (`VISITOR_LINKED_TO_OTHER_MEMBER`)
|
|
576
|
-
* visitor_uid 를 자동 재발급하고 link-member 를 한 번 더 호출 — 한 단계의 자가
|
|
577
|
-
* 복구로 끝나며 무한 재귀를 막기 위해 두 번째 시도는 응답을 더 보지 않는다.
|
|
578
|
-
* - storage_web_id 가 init 안 됐거나 모든 종류의 네트워크 오류 — silent fail.
|
|
579
|
-
*/
|
|
580
|
-
private linkMemberSilent;
|
|
581
|
-
/** 현재 설정된 회원 ID 조회 (미설정 시 null) */
|
|
582
|
-
getMemberId(): string | null;
|
|
583
|
-
/**
|
|
584
|
-
* 히트맵 수집 활성화 (opt-in)
|
|
585
|
-
*/
|
|
586
|
-
enableHeatmap(options?: {
|
|
587
|
-
click?: boolean;
|
|
588
|
-
scroll?: boolean;
|
|
589
|
-
}): void;
|
|
590
|
-
/**
|
|
591
|
-
* 세션 heartbeat 자동 전송 시작 (30초 간격)
|
|
592
|
-
*/
|
|
593
|
-
enableHeartbeat(): void;
|
|
594
|
-
/**
|
|
595
|
-
* 큐에 있는 이벤트 즉시 전송.
|
|
596
|
-
*
|
|
597
|
-
* 기본적으로 이벤트는 배치(10개) 또는 주기(5초)로 flush 되지만, 페이지 이탈 직전이나
|
|
598
|
-
* 결정적 이벤트(결제 완료 등)는 수동으로 `flush()` 를 호출해 전송 지연을 줄일 수 있다.
|
|
599
|
-
*
|
|
600
|
-
* @returns 서버 응답 완료 시까지 대기하는 Promise
|
|
601
|
-
*
|
|
602
|
-
* @example
|
|
603
|
-
* ```ts
|
|
604
|
-
* // 결제 완료 직후 이탈에 대비해 즉시 flush
|
|
605
|
-
* await cb.analytics.track('purchase_completed', { order_id: '123' })
|
|
606
|
-
* await cb.analytics.flush()
|
|
607
|
-
* window.location.href = '/thank-you'
|
|
608
|
-
* ```
|
|
609
|
-
*/
|
|
610
|
-
flush(): Promise<void>;
|
|
611
|
-
/**
|
|
612
|
-
* 인기 페이지 조회 (콘솔 JWT 또는 User Secret Key `cb_sk_` 인증 필요).
|
|
613
|
-
*
|
|
614
|
-
* 브라우저 환경에서 Public Key(`cb_pk_`) 만 가진 SDK 인스턴스로는 호출이 차단된다.
|
|
615
|
-
* Functions / 어드민 앱 등 cb_sk_ 환경에서 사용하라.
|
|
616
|
-
*
|
|
617
|
-
* @param storageWebId 조회할 웹스토리지 ID. 미지정 시 `init()` 에 전달된 ID 사용.
|
|
618
|
-
* @param options 기간/limit 옵션
|
|
619
|
-
* @example
|
|
620
|
-
* ```ts
|
|
621
|
-
* const { pages } = await cb.analytics.getPopularPages('019d8...', { limit: 20 })
|
|
622
|
-
* ```
|
|
623
|
-
*/
|
|
624
|
-
getPopularPages(storageWebId?: string, options?: AnalyticsRangeOptions): Promise<PopularPagesResponse>;
|
|
625
|
-
/**
|
|
626
|
-
* 페이지 전환 플로우(Sankey) 조회 — JWT/cb_sk_ 인증 필요.
|
|
627
|
-
*/
|
|
628
|
-
getNavigationFlow(storageWebId?: string, options?: AnalyticsRangeOptions): Promise<NavigationFlowResponse>;
|
|
629
|
-
/**
|
|
630
|
-
* 방문자 목록 조회 — JWT/cb_sk_ 인증 필요.
|
|
631
|
-
*/
|
|
632
|
-
getVisitors(storageWebId?: string, options?: VisitorListOptions): Promise<VisitorListResponse>;
|
|
633
|
-
/**
|
|
634
|
-
* 멤버별 합산 방문자 그룹 조회 — JWT/cb_sk_ 인증 필요. (1.11+)
|
|
635
|
-
*
|
|
636
|
-
* `getVisitors` 와 달리 visitor row 들을 `app_member_id` 로 합쳐 단일 row 로 반환.
|
|
637
|
-
* 같은 사람이 PC + 모바일 + 태블릿으로 접속한 경우 visitor 3개 → 그룹 1개.
|
|
638
|
-
* 익명 visitor 는 단일 row 로 그대로 포함되어 페이지네이션이 일관됨.
|
|
639
|
-
*
|
|
640
|
-
* @example
|
|
641
|
-
* ```ts
|
|
642
|
-
* const { groups } = await cb.analytics.getVisitorGroups('019d8...', { limit: 50 })
|
|
643
|
-
* for (const g of groups) {
|
|
644
|
-
* if (g.app_member_id) console.log(`${g.app_member_id}: ${g.visitor_count} 디바이스`)
|
|
645
|
-
* }
|
|
646
|
-
* ```
|
|
647
|
-
*/
|
|
648
|
-
getVisitorGroups(storageWebId?: string, options?: VisitorListOptions): Promise<VisitorGroupListResponse>;
|
|
649
|
-
/**
|
|
650
|
-
* 단건 멤버 합산 방문자 조회 — JWT/cb_sk_ 인증 필요. (1.11+)
|
|
651
|
-
*
|
|
652
|
-
* 어드민 회원 상세 페이지처럼 **한 명만 필요**할 때. 페이지네이션 풀 다운 없이
|
|
653
|
-
* 한 번의 호출로 합산 결과 반환.
|
|
654
|
-
*
|
|
655
|
-
* @example
|
|
656
|
-
* ```ts
|
|
657
|
-
* const v = await cb.analytics.getVisitorByMember('019d8...', memberId)
|
|
658
|
-
* console.log(`${v.visitor_count} 디바이스, 총 ${v.total_page_views} pv`)
|
|
659
|
-
* ```
|
|
660
|
-
*/
|
|
661
|
-
getVisitorByMember(storageWebId: string | undefined, memberId: string): Promise<VisitorByMemberResponse>;
|
|
662
|
-
/**
|
|
663
|
-
* 두 visitor 를 한 사람으로 통합하는 admin 작업 — JWT/cb_sk_ 인증 필요. (1.11+)
|
|
664
|
-
*
|
|
665
|
-
* 외부 인증 시스템에서 두 visitor 가 동일인임을 알았을 때 사용. source 의 자식 레코드
|
|
666
|
-
* (page_views, daily, custom_events, experiment_assignments, heatmap_events,
|
|
667
|
-
* session_recordings) 를 target 으로 옮기고 source visitor 는 삭제됨.
|
|
668
|
-
*
|
|
669
|
-
* @param request 둘 중 하나 필수: `target_visitor_uid` 또는 `target_member_id`.
|
|
670
|
-
* @example
|
|
671
|
-
* ```ts
|
|
672
|
-
* await cb.analytics.mergeVisitors('019d8...', {
|
|
673
|
-
* source_visitor_uid: 'old-uid',
|
|
674
|
-
* target_member_id: '01a...',
|
|
675
|
-
* })
|
|
676
|
-
* ```
|
|
677
|
-
*/
|
|
678
|
-
mergeVisitors(storageWebId: string | undefined, request: MergeVisitorsRequest): Promise<MergeVisitorsResponse>;
|
|
679
|
-
/**
|
|
680
|
-
* 조회 메서드 공통 가드 — Public Key 인증 SDK 인스턴스에서는 명확한 에러를 던진다.
|
|
681
|
-
* 백엔드 라우트는 cb_pk_ 를 거부하므로 호출 자체를 막는 것이 디버깅에 유리.
|
|
682
|
-
*/
|
|
683
|
-
private requireServerSideStorageId;
|
|
684
|
-
/**
|
|
685
|
-
* 세션 매니저 접근 (고급 사용자용).
|
|
686
|
-
*
|
|
687
|
-
* 외부에서 세션 ID 를 읽어 자체 로깅에 합치거나 강제 세션 종료/재시작이 필요한 경우
|
|
688
|
-
* 사용. 일반적으로는 AnalyticsAPI 가 내부적으로 세션을 관리하므로 호출할 필요가 없다.
|
|
689
|
-
*
|
|
690
|
-
* @returns 내부 SessionManager 인스턴스
|
|
691
|
-
*/
|
|
692
|
-
getSession(): SessionManager;
|
|
693
|
-
private canTrack;
|
|
694
|
-
private isDNT;
|
|
695
|
-
private createBaseEvent;
|
|
696
|
-
private enqueue;
|
|
697
|
-
private flushQueue;
|
|
698
|
-
/**
|
|
699
|
-
* sendBeacon 으로 동기 flush (beforeunload 용).
|
|
700
|
-
*
|
|
701
|
-
* sendBeacon 은 일반 fetch 와 달리 User-Agent 헤더가 신뢰할 수 있지만, 백엔드 봇
|
|
702
|
-
* 탐지가 body 의 `user_agent` 필드 첫 번째 값만 보므로 여기서도 동일하게 채워
|
|
703
|
-
* 첫 방문이 unload 타이밍에 도달했을 때 봇으로 오판되는 것을 방지한다.
|
|
704
|
-
*/
|
|
705
|
-
private flushSync;
|
|
706
|
-
private trackSessionStart;
|
|
707
|
-
private startBatchTimer;
|
|
708
|
-
private stopBatchTimer;
|
|
709
|
-
private startHeartbeat;
|
|
710
|
-
private stopHeartbeat;
|
|
711
|
-
/** 하트비트를 큐에 넣어 배치 전송 */
|
|
712
|
-
private sendHeartbeat;
|
|
713
|
-
/** sendBeacon으로 하트비트 전송 (unload/visibility hidden용) */
|
|
714
|
-
private sendHeartbeatBeacon;
|
|
715
|
-
private setupAutoPageView;
|
|
716
|
-
private removeAutoPageView;
|
|
717
|
-
private removeHeatmapListeners;
|
|
718
|
-
private handleHeatmapClick;
|
|
719
|
-
private recordHeatmapEvent;
|
|
720
|
-
private heatmapQueue;
|
|
721
|
-
private log;
|
|
722
58
|
}
|
|
723
59
|
|
|
724
60
|
/** 앱 멤버 게스트 가입 응답 */
|
|
@@ -757,20 +93,16 @@ interface MemberInfoResponse {
|
|
|
757
93
|
member_id: string;
|
|
758
94
|
nickname: string;
|
|
759
95
|
is_active: boolean;
|
|
760
|
-
custom_data: Record<string,
|
|
761
|
-
/** 멤버 이메일 (EMAIL identity 에서 추출, 없으면 빈 문자열) */
|
|
762
|
-
email?: string;
|
|
763
|
-
/** 멤버 역할 — RLS 규칙에서 `auth.role` 로 참조 (예: "admin", "moderator") */
|
|
764
|
-
role?: string;
|
|
96
|
+
custom_data: Record<string, any>;
|
|
765
97
|
}
|
|
766
98
|
/** 앱 멤버 custom_data 수정 요청 */
|
|
767
99
|
interface UpdateCustomDataRequest {
|
|
768
|
-
custom_data: Record<string,
|
|
100
|
+
custom_data: Record<string, any>;
|
|
769
101
|
}
|
|
770
102
|
/** 앱 멤버 custom_data 수정 응답 */
|
|
771
103
|
interface UpdateCustomDataResponse {
|
|
772
104
|
member_id: string;
|
|
773
|
-
custom_data: Record<string,
|
|
105
|
+
custom_data: Record<string, any>;
|
|
774
106
|
}
|
|
775
107
|
/** 앱 인증 설정 응답 */
|
|
776
108
|
interface AuthSettingsResponse {
|
|
@@ -786,14 +118,7 @@ declare class AuthAPI {
|
|
|
786
118
|
private http;
|
|
787
119
|
private guestMemberLoginPromise;
|
|
788
120
|
private cachedGuestMemberTokenKey;
|
|
789
|
-
private analytics;
|
|
790
121
|
constructor(http: HttpClient);
|
|
791
|
-
/**
|
|
792
|
-
* AnalyticsAPI 주입 — 로그인/가입/로그아웃 시 방문자 트래커에 member_id 를 전달하여
|
|
793
|
-
* 게스트 방문자를 회원과 연결한다. ConnectBase 컨스트럭터에서 내부적으로 호출된다.
|
|
794
|
-
*/
|
|
795
|
-
_attachAnalytics(analytics: AnalyticsAPI): void;
|
|
796
|
-
private notifyVisitorTracker;
|
|
797
122
|
/**
|
|
798
123
|
* 앱의 인증 설정 조회
|
|
799
124
|
* 어떤 로그인 방식이 허용되는지 확인합니다.
|
|
@@ -883,44 +208,6 @@ declare class AuthAPI {
|
|
|
883
208
|
* ```
|
|
884
209
|
*/
|
|
885
210
|
updateCustomData(data: UpdateCustomDataRequest): Promise<UpdateCustomDataResponse>;
|
|
886
|
-
/**
|
|
887
|
-
* Admin: 다른 멤버의 정보를 수정합니다 (role / nickname / custom_data).
|
|
888
|
-
*
|
|
889
|
-
* 이 메서드는 RLS 의 `auth.role` 평가에 사용되는 `member.role` 필드를 set 할 수 있는
|
|
890
|
-
* 유일한 SDK 경로입니다. 보안상 AppMember 자신의 self-update 는 허용되지 않습니다
|
|
891
|
-
* (권한 상승 우회 차단) — 이 메서드는 cb_sk_ admin secret key 권한 컨텍스트에서만
|
|
892
|
-
* 호출 가능합니다.
|
|
893
|
-
*
|
|
894
|
-
* 사전 조건:
|
|
895
|
-
* - ConnectBase 인스턴스가 `publicKey` 와 `secretKey` 를 모두 가지고 있어야 함
|
|
896
|
-
* - secretKey 의 user 가 해당 앱에 권한을 가지고 있어야 함 (서버에서 검증)
|
|
897
|
-
*
|
|
898
|
-
* @example
|
|
899
|
-
* ```typescript
|
|
900
|
-
* const cb = new ConnectBase({ publicKey: 'cb_pk_...', secretKey: 'cb_sk_...' })
|
|
901
|
-
* await cb.auth.adminUpdateMember('member-uuid', { role: 'admin' })
|
|
902
|
-
*
|
|
903
|
-
* // role 해제
|
|
904
|
-
* await cb.auth.adminUpdateMember('member-uuid', { role: '' })
|
|
905
|
-
*
|
|
906
|
-
* // 다중 필드
|
|
907
|
-
* await cb.auth.adminUpdateMember('member-uuid', {
|
|
908
|
-
* nickname: 'Alice',
|
|
909
|
-
* role: 'editor',
|
|
910
|
-
* custom_data: { level: 5 }
|
|
911
|
-
* })
|
|
912
|
-
* ```
|
|
913
|
-
*/
|
|
914
|
-
adminUpdateMember(memberID: string, fields: {
|
|
915
|
-
nickname?: string;
|
|
916
|
-
role?: string;
|
|
917
|
-
custom_data?: Record<string, unknown>;
|
|
918
|
-
}): Promise<{
|
|
919
|
-
member_id: string;
|
|
920
|
-
nickname: string;
|
|
921
|
-
custom_data: Record<string, unknown>;
|
|
922
|
-
role: string;
|
|
923
|
-
}>;
|
|
924
211
|
/**
|
|
925
212
|
* 로그아웃
|
|
926
213
|
*/
|
|
@@ -936,51 +223,26 @@ declare class AuthAPI {
|
|
|
936
223
|
private storeGuestMemberTokens;
|
|
937
224
|
}
|
|
938
225
|
|
|
939
|
-
|
|
940
|
-
* 서버(data-server `ent/schema/table.go` — `ValidSchemaTypes`) 가 허용하는 컬럼 타입 목록.
|
|
941
|
-
* - `string` / `number` / `int` : 문자열 / 숫자(float) / 정수
|
|
942
|
-
* - `bool` : 참/거짓 (JS 의 `boolean` 이 아니라 `bool` 입니다)
|
|
943
|
-
* - `uuid` : UUID 문자열
|
|
944
|
-
* - `date` : ISO-8601 날짜/시간
|
|
945
|
-
* - `object` / `array` : 중첩 JSON
|
|
946
|
-
*/
|
|
947
|
-
type DataType = 'string' | 'int' | 'number' | 'bool' | 'uuid' | 'date' | 'object' | 'array';
|
|
948
|
-
/**
|
|
949
|
-
* 컬럼 정보 (Table.schema 맵에서 합성된 객체).
|
|
950
|
-
*
|
|
951
|
-
* 서버는 컬럼을 별도 레코드로 저장하지 않으므로 `id` 는 컬럼 이름과 동일하며,
|
|
952
|
-
* `order` 는 SDK 가 맵 순서대로 부여한 인덱스입니다. `created_at` 은 테이블의
|
|
953
|
-
* `created_at` 으로 대체됩니다.
|
|
954
|
-
*/
|
|
226
|
+
type DataType = 'string' | 'number' | 'boolean' | 'date' | 'object' | 'array';
|
|
955
227
|
interface ColumnSchema {
|
|
956
|
-
/** 컬럼 이름과 동일 (서버 별도 ID 없음) */
|
|
957
228
|
id: string;
|
|
958
229
|
name: string;
|
|
959
230
|
data_type: DataType;
|
|
960
231
|
is_required: boolean;
|
|
961
|
-
default_value?:
|
|
962
|
-
|
|
963
|
-
encrypted?: boolean;
|
|
964
|
-
/** SDK 가 맵 순서대로 부여한 인덱스 */
|
|
232
|
+
default_value?: string;
|
|
233
|
+
validation_rule?: string;
|
|
965
234
|
order: number;
|
|
966
|
-
|
|
235
|
+
description?: string;
|
|
967
236
|
created_at: string;
|
|
968
|
-
/**
|
|
969
|
-
* @deprecated 서버가 지원하지 않습니다.
|
|
970
|
-
*/
|
|
971
|
-
validation_rule?: string;
|
|
972
|
-
/**
|
|
973
|
-
* @deprecated 컬럼 개별 타임스탬프가 없습니다.
|
|
974
|
-
*/
|
|
975
237
|
updated_at?: string;
|
|
976
238
|
}
|
|
977
239
|
interface CreateColumnRequest {
|
|
978
240
|
name: string;
|
|
979
241
|
data_type: DataType;
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
242
|
+
is_required: boolean;
|
|
243
|
+
default_value?: string;
|
|
244
|
+
validation_rule?: string;
|
|
245
|
+
order: number;
|
|
984
246
|
description?: string;
|
|
985
247
|
/**
|
|
986
248
|
* 필드 레벨 암호화 활성화 여부.
|
|
@@ -989,172 +251,26 @@ interface CreateColumnRequest {
|
|
|
989
251
|
* 서버에 SECRET_ENCRYPTION_KEY가 설정되어 있어야 합니다.
|
|
990
252
|
*/
|
|
991
253
|
encrypted?: boolean;
|
|
992
|
-
/**
|
|
993
|
-
* @deprecated 서버가 무시합니다. 컬럼 순서는 서버가 자동 관리합니다.
|
|
994
|
-
*/
|
|
995
|
-
order?: number;
|
|
996
|
-
/**
|
|
997
|
-
* @deprecated 서버가 해당 필드를 저장하지 않습니다.
|
|
998
|
-
*/
|
|
999
|
-
validation_rule?: string;
|
|
1000
254
|
}
|
|
1001
255
|
interface UpdateColumnRequest {
|
|
256
|
+
name?: string;
|
|
1002
257
|
data_type?: DataType;
|
|
1003
258
|
is_required?: boolean;
|
|
1004
|
-
default_value?:
|
|
1005
|
-
description?: string;
|
|
1006
|
-
encrypted?: boolean;
|
|
1007
|
-
/**
|
|
1008
|
-
* @deprecated 서버가 컬럼 이름 변경을 지원하지 않습니다. 변경하려면
|
|
1009
|
-
* 삭제 후 재생성하거나 data-server 의 rename 엔드포인트를 사용하세요.
|
|
1010
|
-
*/
|
|
1011
|
-
name?: string;
|
|
1012
|
-
/**
|
|
1013
|
-
* @deprecated 서버가 무시합니다.
|
|
1014
|
-
*/
|
|
1015
|
-
order?: number;
|
|
1016
|
-
/**
|
|
1017
|
-
* @deprecated 서버가 해당 필드를 저장하지 않습니다.
|
|
1018
|
-
*/
|
|
259
|
+
default_value?: string;
|
|
1019
260
|
validation_rule?: string;
|
|
261
|
+
order?: number;
|
|
262
|
+
description?: string;
|
|
1020
263
|
}
|
|
1021
|
-
/**
|
|
1022
|
-
* 서버(data-server `ent/schema/table.go` 의 `Table`) 가 반환하는 테이블 레코드.
|
|
1023
|
-
* 필드 이름은 Go ent 모델과 일치합니다.
|
|
1024
|
-
*/
|
|
1025
264
|
interface TableSchema {
|
|
1026
265
|
id: string;
|
|
1027
|
-
|
|
1028
|
-
/** 테이블 이름 (ent 필드: `title`) */
|
|
1029
|
-
title: string;
|
|
1030
|
-
/** 평면 스키마 맵. 컬럼 객체 배열로 변환하려면 `getColumns()` 사용. */
|
|
1031
|
-
schema: TableSchemaDefinition;
|
|
1032
|
-
/** 검증 스키마 (table-level). 설정되어 있으면 데이터 insert/update 시 평가됨. */
|
|
1033
|
-
validation_schema?: ValidationSchema;
|
|
1034
|
-
access_level: TableAccessLevel;
|
|
1035
|
-
is_active: boolean;
|
|
1036
|
-
created_at: string;
|
|
1037
|
-
updated_at: string;
|
|
1038
|
-
}
|
|
1039
|
-
/**
|
|
1040
|
-
* 컬럼 정의. 서버는 두 가지 형식 중 하나로 저장합니다:
|
|
1041
|
-
* - 플랫: 타입 문자열만 (`'string'`, `'int'` 등)
|
|
1042
|
-
* - 중첩: 타입 + 추가 속성 객체 (`{type, required, default, description, encrypted}`)
|
|
1043
|
-
*
|
|
1044
|
-
* 클라이언트에서 `createTable` 시에는 플랫 형태가 권장되며, 추가 속성은
|
|
1045
|
-
* `createColumn` 을 사용하거나 중첩 객체로 직접 지정할 수 있습니다.
|
|
1046
|
-
*/
|
|
1047
|
-
type TableColumnDef = DataType | {
|
|
1048
|
-
type: DataType;
|
|
1049
|
-
required?: boolean;
|
|
1050
|
-
default?: unknown;
|
|
266
|
+
name: string;
|
|
1051
267
|
description?: string;
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
* 테이블 스키마 정의.
|
|
1056
|
-
* 키는 컬럼 이름, 값은 타입 문자열 또는 중첩 컬럼 객체입니다.
|
|
1057
|
-
* `$required` 는 특수 키로, 필수 컬럼 이름의 배열을 받습니다.
|
|
1058
|
-
*
|
|
1059
|
-
* @example
|
|
1060
|
-
* ```ts
|
|
1061
|
-
* // 플랫 형태
|
|
1062
|
-
* { email: 'string', age: 'int', $required: ['email'] }
|
|
1063
|
-
*
|
|
1064
|
-
* // 중첩 형태 (필드별 옵션)
|
|
1065
|
-
* { email: { type: 'string', required: true, encrypted: true } }
|
|
1066
|
-
* ```
|
|
1067
|
-
*/
|
|
1068
|
-
interface TableSchemaDefinition {
|
|
1069
|
-
/** 필수 컬럼 이름 목록 (서버 hook 이 `$required` 키로 해석) */
|
|
1070
|
-
$required?: string[];
|
|
1071
|
-
/** 컬럼명 → 컬럼 정의. `$required` 키는 예외적으로 `string[]` */
|
|
1072
|
-
[columnName: string]: TableColumnDef | string[] | undefined;
|
|
1073
|
-
}
|
|
1074
|
-
/** 테이블 접근 수준 */
|
|
1075
|
-
type TableAccessLevel = 'Creator' | 'Public' | 'AppMember';
|
|
1076
|
-
/** 단일 필드의 검증 규칙 */
|
|
1077
|
-
interface ValidationSchemaField {
|
|
1078
|
-
/** 데이터 타입 */
|
|
1079
|
-
type: DataType;
|
|
1080
|
-
/** 필수 여부 */
|
|
1081
|
-
required?: boolean;
|
|
1082
|
-
/** 기본값 */
|
|
1083
|
-
default?: unknown;
|
|
1084
|
-
/** 숫자 최소값 */
|
|
1085
|
-
min?: number;
|
|
1086
|
-
/** 숫자 최대값 */
|
|
1087
|
-
max?: number;
|
|
1088
|
-
/** 문자열 최소 길이 */
|
|
1089
|
-
minLength?: number;
|
|
1090
|
-
/** 문자열 최대 길이 */
|
|
1091
|
-
maxLength?: number;
|
|
1092
|
-
/** 정규식 패턴 (Go regexp 호환) */
|
|
1093
|
-
pattern?: string;
|
|
1094
|
-
/** 허용 값 목록 */
|
|
1095
|
-
enum?: unknown[];
|
|
1096
|
-
/** 배열 아이템 스키마 */
|
|
1097
|
-
items?: ValidationSchemaField;
|
|
1098
|
-
/** object 의 속성 스키마 */
|
|
1099
|
-
properties?: Record<string, ValidationSchemaField>;
|
|
1100
|
-
/** 수정 불가 (immutable) */
|
|
1101
|
-
immutable?: boolean;
|
|
1102
|
-
/** 유니크 제약 */
|
|
1103
|
-
unique?: boolean;
|
|
1104
|
-
/** 새니타이징 ('html', 'xss', 'trim') */
|
|
1105
|
-
sanitize?: string;
|
|
1106
|
-
/** 자동 계산 표현식 */
|
|
1107
|
-
computed?: string;
|
|
1108
|
-
/** 상태 전이 규칙: 현재상태 → 허용되는 다음 상태들 */
|
|
1109
|
-
transitions?: Record<string, string[]>;
|
|
1110
|
-
}
|
|
1111
|
-
/** 상태 전이 규칙 (객체 단위 — 필드 + 전이 맵) */
|
|
1112
|
-
interface ValidationStateTransitions {
|
|
1113
|
-
field: string;
|
|
1114
|
-
transitions: Record<string, string[]>;
|
|
1115
|
-
}
|
|
1116
|
-
/**
|
|
1117
|
-
* 테이블 검증 스키마 (table-level).
|
|
1118
|
-
* 데이터 insert/update 시 자동으로 평가됩니다.
|
|
1119
|
-
*
|
|
1120
|
-
* @example
|
|
1121
|
-
* ```ts
|
|
1122
|
-
* {
|
|
1123
|
-
* fields: {
|
|
1124
|
-
* email: { type: 'string', pattern: '^.+@.+$', required: true },
|
|
1125
|
-
* age: { type: 'int', min: 0, max: 150 }
|
|
1126
|
-
* },
|
|
1127
|
-
* required: ['email'],
|
|
1128
|
-
* immutable: ['email']
|
|
1129
|
-
* }
|
|
1130
|
-
* ```
|
|
1131
|
-
*/
|
|
1132
|
-
interface ValidationSchema {
|
|
1133
|
-
fields: Record<string, ValidationSchemaField>;
|
|
1134
|
-
required?: string[];
|
|
1135
|
-
unique?: string[];
|
|
1136
|
-
immutable?: string[];
|
|
1137
|
-
computed?: Record<string, string>;
|
|
1138
|
-
transitions?: Record<string, ValidationStateTransitions>;
|
|
268
|
+
columns: ColumnSchema[];
|
|
269
|
+
created_at: string;
|
|
270
|
+
updated_at?: string;
|
|
1139
271
|
}
|
|
1140
272
|
interface CreateTableRequest {
|
|
1141
|
-
/** 테이블 이름 (서버는 내부적으로 `title` 로 저장) */
|
|
1142
273
|
name: string;
|
|
1143
|
-
/**
|
|
1144
|
-
* 초기 컬럼 스키마 (선택).
|
|
1145
|
-
* 생략하면 컬럼이 없는 빈 테이블로 생성되며, 이후 `addColumn()` 으로 추가할 수 있습니다.
|
|
1146
|
-
*/
|
|
1147
|
-
schema?: TableSchemaDefinition;
|
|
1148
|
-
/**
|
|
1149
|
-
* 접근 수준 (선택, 기본값 `'Creator'`).
|
|
1150
|
-
* - `Creator`: 테이블 생성자만 전체 권한
|
|
1151
|
-
* - `Public`: 누구나 읽기/쓰기
|
|
1152
|
-
* - `AppMember`: 앱 멤버만 읽기/쓰기
|
|
1153
|
-
*/
|
|
1154
|
-
accessLevel?: TableAccessLevel;
|
|
1155
|
-
/**
|
|
1156
|
-
* @deprecated 서버에 저장되지 않습니다. 필드는 backward-compat 을 위해 남아있으며 SDK 가 서버로 전송하지 않습니다.
|
|
1157
|
-
*/
|
|
1158
274
|
description?: string;
|
|
1159
275
|
}
|
|
1160
276
|
interface DataItem {
|
|
@@ -1169,21 +285,9 @@ interface CreateDataRequest {
|
|
|
1169
285
|
interface UpdateDataRequest {
|
|
1170
286
|
data: Record<string, unknown>;
|
|
1171
287
|
}
|
|
1172
|
-
/**
|
|
1173
|
-
* 테이블 데이터 조회 응답.
|
|
1174
|
-
*
|
|
1175
|
-
* 서버(data-server `internal_data_controller.go` 의 `FetchDataByTableGET`,
|
|
1176
|
-
* `QueryDataByTable`) 가 반환하는 JSON 과 1:1 매핑합니다.
|
|
1177
|
-
*
|
|
1178
|
-
* 참고: `1.3.0` 이전 버전(`0.16.1` 기준)에서는 `datas` / `total_size` 로
|
|
1179
|
-
* 선언돼 있었으나, 실제 서버 wire 포맷은 `data` / `total_count` 이므로 런타임에
|
|
1180
|
-
* 속성 접근이 `undefined` 를 반환하는 결함이 있었습니다. `1.4.0` 에서 바로잡습니다.
|
|
1181
|
-
*/
|
|
1182
288
|
interface FetchDataResponse {
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
/** 총 매칭 문서 수 */
|
|
1186
|
-
total_count: number;
|
|
289
|
+
datas: DataItem[];
|
|
290
|
+
total_size: number;
|
|
1187
291
|
}
|
|
1188
292
|
interface QueryOptions {
|
|
1189
293
|
limit?: number;
|
|
@@ -1330,7 +434,7 @@ interface PopulateOption {
|
|
|
1330
434
|
populate?: PopulateOption[];
|
|
1331
435
|
}
|
|
1332
436
|
type TriggerEvent = 'create' | 'update' | 'delete' | 'all';
|
|
1333
|
-
type TriggerHandlerType = 'function' | 'workflow' | 'webhook'
|
|
437
|
+
type TriggerHandlerType = 'function' | 'workflow' | 'webhook';
|
|
1334
438
|
interface Trigger {
|
|
1335
439
|
id: string;
|
|
1336
440
|
app_id: string;
|
|
@@ -1341,7 +445,6 @@ interface Trigger {
|
|
|
1341
445
|
handler_type: TriggerHandlerType;
|
|
1342
446
|
handler_id?: string;
|
|
1343
447
|
handler_url?: string;
|
|
1344
|
-
handler_action?: Record<string, unknown>;
|
|
1345
448
|
is_active: boolean;
|
|
1346
449
|
order: number;
|
|
1347
450
|
created_at: string;
|
|
@@ -1354,7 +457,6 @@ interface CreateTriggerRequest {
|
|
|
1354
457
|
handler_type: TriggerHandlerType;
|
|
1355
458
|
handler_id?: string;
|
|
1356
459
|
handler_url?: string;
|
|
1357
|
-
handler_action?: Record<string, unknown>;
|
|
1358
460
|
condition?: Record<string, unknown>;
|
|
1359
461
|
is_active?: boolean;
|
|
1360
462
|
order?: number;
|
|
@@ -1365,7 +467,6 @@ interface UpdateTriggerRequest {
|
|
|
1365
467
|
handler_type?: TriggerHandlerType;
|
|
1366
468
|
handler_id?: string;
|
|
1367
469
|
handler_url?: string;
|
|
1368
|
-
handler_action?: Record<string, unknown>;
|
|
1369
470
|
condition?: Record<string, unknown>;
|
|
1370
471
|
is_active?: boolean;
|
|
1371
472
|
order?: number;
|
|
@@ -1487,31 +588,6 @@ interface TransactionWrite {
|
|
|
1487
588
|
exists?: boolean;
|
|
1488
589
|
};
|
|
1489
590
|
}
|
|
1490
|
-
interface BatchOperationResult {
|
|
1491
|
-
index: number;
|
|
1492
|
-
success: boolean;
|
|
1493
|
-
doc_id?: string;
|
|
1494
|
-
error?: string;
|
|
1495
|
-
}
|
|
1496
|
-
interface BatchWriteResult {
|
|
1497
|
-
success: boolean;
|
|
1498
|
-
results: BatchOperationResult[];
|
|
1499
|
-
total_count?: number;
|
|
1500
|
-
success_count?: number;
|
|
1501
|
-
failed_count?: number;
|
|
1502
|
-
}
|
|
1503
|
-
interface TransactionWriteResult {
|
|
1504
|
-
index: number;
|
|
1505
|
-
doc_id?: string;
|
|
1506
|
-
success: boolean;
|
|
1507
|
-
}
|
|
1508
|
-
interface TransactionResult {
|
|
1509
|
-
success: boolean;
|
|
1510
|
-
transaction_id?: string;
|
|
1511
|
-
reads?: Record<string, unknown>;
|
|
1512
|
-
results?: TransactionWriteResult[];
|
|
1513
|
-
error?: string;
|
|
1514
|
-
}
|
|
1515
591
|
interface TTLConfig {
|
|
1516
592
|
table_name: string;
|
|
1517
593
|
field: string;
|
|
@@ -1603,11 +679,7 @@ interface DatabaseRealtimeSubscription {
|
|
|
1603
679
|
}
|
|
1604
680
|
/** 데이터베이스 실시간 연결 옵션 */
|
|
1605
681
|
interface DatabaseRealtimeConnectOptions {
|
|
1606
|
-
/**
|
|
1607
|
-
* 액세스 토큰 (필수). 두 종류를 모두 지원:
|
|
1608
|
-
* - 앱 멤버(AppMember) JWT — 자기 앱의 테이블 구독
|
|
1609
|
-
* - cross-app OAuth access token — Provider 앱의 테이블 구독 (`database:read` scope 필요)
|
|
1610
|
-
*/
|
|
682
|
+
/** JWT 액세스 토큰 (필수) */
|
|
1611
683
|
accessToken: string;
|
|
1612
684
|
/** data-server URL (기본: baseUrl) */
|
|
1613
685
|
dataServerUrl?: string;
|
|
@@ -1618,6 +690,14 @@ interface DatabaseRealtimeConnectOptions {
|
|
|
1618
690
|
/** 디버그 로깅 (기본: false) */
|
|
1619
691
|
debug?: boolean;
|
|
1620
692
|
}
|
|
693
|
+
/** 데이터베이스 실시간 프레즌스 상태 */
|
|
694
|
+
interface DatabasePresenceState {
|
|
695
|
+
user_id: string;
|
|
696
|
+
status: 'online' | 'away' | 'offline';
|
|
697
|
+
last_seen: string;
|
|
698
|
+
device?: string;
|
|
699
|
+
metadata?: Record<string, unknown>;
|
|
700
|
+
}
|
|
1621
701
|
interface CreateBackupRequest {
|
|
1622
702
|
/** 백업 이름 */
|
|
1623
703
|
name: string;
|
|
@@ -1672,17 +752,6 @@ interface ExportDataResponse {
|
|
|
1672
752
|
data?: Record<string, unknown>;
|
|
1673
753
|
schema?: Record<string, unknown>;
|
|
1674
754
|
}
|
|
1675
|
-
/**
|
|
1676
|
-
* 데이터 가져오기 요청
|
|
1677
|
-
* @example
|
|
1678
|
-
* {
|
|
1679
|
-
* data: {
|
|
1680
|
-
* users: { rows: [{ name: 'Alice', age: 30 }] },
|
|
1681
|
-
* orders: { rows: [{ user: 'Alice', amount: 1000 }] }
|
|
1682
|
-
* },
|
|
1683
|
-
* mode: 'merge'
|
|
1684
|
-
* }
|
|
1685
|
-
*/
|
|
1686
755
|
interface ImportDataRequest {
|
|
1687
756
|
/** 가져올 데이터: { "테이블이름": { "rows": [{...}, ...] }, ... } */
|
|
1688
757
|
data: Record<string, {
|
|
@@ -1803,109 +872,37 @@ declare class DatabaseAPI {
|
|
|
1803
872
|
private activeSubscriptions;
|
|
1804
873
|
constructor(http: HttpClient);
|
|
1805
874
|
/**
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1808
|
-
* 서버의 테이블/컬럼/데이터 CRUD 는 모두 `/v1/public/*` 경로에서만 제공되며
|
|
1809
|
-
* (core-server → data-server 프록시), JWT 기반 `/v1/*` 경로는 존재하지 않습니다.
|
|
1810
|
-
* 따라서 항상 `/v1/public` 을 사용합니다. 인증은 `X-Public-Key` 헤더에
|
|
1811
|
-
* `publicKey` (`cb_pk_*`) 를 실어 서버가 검증합니다.
|
|
875
|
+
* API Key 인증 시 /v1/public 접두사 반환
|
|
1812
876
|
*/
|
|
1813
877
|
private getPublicPrefix;
|
|
1814
878
|
/**
|
|
1815
879
|
* 테이블 목록 조회
|
|
1816
880
|
*/
|
|
1817
|
-
getTables(): Promise<TableSchema[]>;
|
|
1818
|
-
/**
|
|
1819
|
-
* 테이블 상세 조회
|
|
1820
|
-
*/
|
|
1821
|
-
getTable(tableId: string): Promise<TableSchema>;
|
|
1822
|
-
/**
|
|
1823
|
-
* 테이블 생성.
|
|
1824
|
-
*
|
|
1825
|
-
* 서버 DTO (`{title, schema, access_level}`) 로 변환하여 전송합니다.
|
|
1826
|
-
* `schema` 가 비어있으면 요청 본문에서 키 자체를 생략하여 빈 테이블을
|
|
1827
|
-
* 생성합니다. (서버는 explicit 빈 맵을 거부)
|
|
1828
|
-
*
|
|
1829
|
-
* 서버는 `{message}` 만 돌려주므로 반환 타입은 `void` 입니다.
|
|
1830
|
-
* 생성된 테이블 메타데이터가 필요하면 이어서 `getTables()` 로 조회하세요.
|
|
1831
|
-
*/
|
|
1832
|
-
createTable(data: CreateTableRequest): Promise<void>;
|
|
881
|
+
getTables(databaseId: string): Promise<TableSchema[]>;
|
|
1833
882
|
/**
|
|
1834
|
-
* 테이블
|
|
1835
|
-
*
|
|
1836
|
-
* `name` 은 서버의 `title` 로, `accessLevel` 은 `access_level` 로 매핑됩니다.
|
|
883
|
+
* 테이블 생성
|
|
1837
884
|
*/
|
|
1838
|
-
|
|
885
|
+
createTable(databaseId: string, data: CreateTableRequest): Promise<TableSchema>;
|
|
1839
886
|
/**
|
|
1840
887
|
* 테이블 삭제
|
|
1841
888
|
*/
|
|
1842
|
-
deleteTable(tableId: string): Promise<void>;
|
|
1843
|
-
/**
|
|
1844
|
-
* 테이블 검증 스키마 조회.
|
|
1845
|
-
*
|
|
1846
|
-
* 검증 스키마가 설정되어 있지 않으면 `null` 을 반환합니다.
|
|
1847
|
-
* Public Key 인증으로 호출 가능 (조회 권한).
|
|
1848
|
-
*/
|
|
1849
|
-
getValidationSchema(tableId: string): Promise<ValidationSchema | null>;
|
|
889
|
+
deleteTable(databaseId: string, tableId: string): Promise<void>;
|
|
1850
890
|
/**
|
|
1851
|
-
*
|
|
1852
|
-
*
|
|
1853
|
-
* **권한**: 콘솔 (앱 소유자 JWT) 전용. Public Key 로는 설정 불가.
|
|
1854
|
-
* SDK 에서는 `accessToken` 이 설정되어 있어야 하며, 콘솔에서 사용하는 패턴입니다.
|
|
1855
|
-
*
|
|
1856
|
-
* 빈 fields 는 거부됩니다. 검증 스키마를 제거하려면 `deleteValidationSchema` 사용.
|
|
1857
|
-
*
|
|
1858
|
-
* @example
|
|
1859
|
-
* ```ts
|
|
1860
|
-
* await cb.database.setValidationSchema(tableId, {
|
|
1861
|
-
* fields: {
|
|
1862
|
-
* email: { type: 'string', pattern: '^.+@.+$', required: true },
|
|
1863
|
-
* age: { type: 'int', min: 0, max: 150 }
|
|
1864
|
-
* },
|
|
1865
|
-
* required: ['email'],
|
|
1866
|
-
* immutable: ['email']
|
|
1867
|
-
* })
|
|
1868
|
-
* ```
|
|
1869
|
-
*/
|
|
1870
|
-
setValidationSchema(tableId: string, schema: ValidationSchema): Promise<void>;
|
|
1871
|
-
/**
|
|
1872
|
-
* 테이블 검증 스키마 제거 (schemaless 모드로 복귀).
|
|
1873
|
-
*
|
|
1874
|
-
* **권한**: 콘솔 (앱 소유자 JWT) 전용.
|
|
1875
|
-
*/
|
|
1876
|
-
deleteValidationSchema(tableId: string): Promise<void>;
|
|
1877
|
-
/**
|
|
1878
|
-
* appId 가 설정되어 있어야 콘솔 경로를 호출할 수 있습니다 (validation_schema set/delete).
|
|
1879
|
-
*/
|
|
1880
|
-
private requireAppId;
|
|
1881
|
-
/**
|
|
1882
|
-
* 컬럼 목록 조회 (`Table.schema` 맵을 컬럼 객체 배열로 변환).
|
|
1883
|
-
*
|
|
1884
|
-
* 서버는 컬럼을 다음 두 가지 중 하나로 저장합니다:
|
|
1885
|
-
* - 플랫: `"email": "string"` (추가 속성이 없는 경우)
|
|
1886
|
-
* - 중첩: `"email": { "type": "string", "required": true, ... }` (추가 속성이 있는 경우)
|
|
1887
|
-
*
|
|
1888
|
-
* `$required` 키는 별도 배열로 필수 컬럼을 지정할 수 있으며, 중첩 객체의
|
|
1889
|
-
* `required: true` 와 병합되어 판정됩니다.
|
|
891
|
+
* 컬럼 목록 조회
|
|
1890
892
|
*/
|
|
1891
893
|
getColumns(tableId: string): Promise<ColumnSchema[]>;
|
|
1892
894
|
/**
|
|
1893
|
-
* 컬럼
|
|
1894
|
-
*
|
|
1895
|
-
* 서버는 `{message}` 만 돌려주므로 반환 타입은 `void` 입니다.
|
|
1896
|
-
* 생성 결과 컬럼을 얻으려면 이어서 `getColumns(tableId)` 로 조회하세요.
|
|
895
|
+
* 컬럼 생성
|
|
1897
896
|
*/
|
|
1898
|
-
createColumn(tableId: string, data: CreateColumnRequest): Promise<
|
|
897
|
+
createColumn(tableId: string, data: CreateColumnRequest): Promise<ColumnSchema>;
|
|
1899
898
|
/**
|
|
1900
|
-
* 컬럼
|
|
1901
|
-
*
|
|
1902
|
-
* 서버는 `{message}` 만 돌려주므로 반환 타입은 `void` 입니다.
|
|
899
|
+
* 컬럼 수정
|
|
1903
900
|
*/
|
|
1904
|
-
updateColumn(tableId: string,
|
|
901
|
+
updateColumn(tableId: string, columnId: string, data: UpdateColumnRequest): Promise<ColumnSchema>;
|
|
1905
902
|
/**
|
|
1906
903
|
* 컬럼 삭제
|
|
1907
904
|
*/
|
|
1908
|
-
deleteColumn(tableId: string,
|
|
905
|
+
deleteColumn(tableId: string, columnId: string): Promise<void>;
|
|
1909
906
|
/**
|
|
1910
907
|
* 데이터 조회 (페이지네이션)
|
|
1911
908
|
*/
|
|
@@ -1919,19 +916,9 @@ declare class DatabaseAPI {
|
|
|
1919
916
|
*/
|
|
1920
917
|
getDataById(tableId: string, dataId: string): Promise<DataItem>;
|
|
1921
918
|
/**
|
|
1922
|
-
* 데이터
|
|
1923
|
-
*
|
|
1924
|
-
* `tableIdOrName` 은 테이블 UUID 또는 이름. UUID 형식이면 기존 경로
|
|
1925
|
-
* (`/tables/:tableId/data`), 그렇지 않으면 이름 기반 경로
|
|
1926
|
-
* (`/tables/name/:tableName/data`) 를 사용합니다.
|
|
1927
|
-
*
|
|
1928
|
-
* `options.autoCreate: true` 시 테이블이 없으면 빈 schemaless 테이블을
|
|
1929
|
-
* 자동으로 생성한 뒤 insert. opt-in 이며 프로토타입/AI 자동화 워크플로에
|
|
1930
|
-
* 권장합니다. production 앱은 명시적 `createTable` 호출 권장.
|
|
919
|
+
* 데이터 생성
|
|
1931
920
|
*/
|
|
1932
|
-
createData(
|
|
1933
|
-
autoCreate?: boolean;
|
|
1934
|
-
}): Promise<DataItem>;
|
|
921
|
+
createData(tableId: string, data: CreateDataRequest): Promise<DataItem>;
|
|
1935
922
|
/**
|
|
1936
923
|
* 데이터 수정 (부분 업데이트)
|
|
1937
924
|
* 제공된 필드만 수정되고, 기존 필드는 유지됩니다.
|
|
@@ -1972,18 +959,16 @@ declare class DatabaseAPI {
|
|
|
1972
959
|
}): Promise<GeoResponse>;
|
|
1973
960
|
/**
|
|
1974
961
|
* 배치 쓰기 (여러 테이블 다중 문서 원자적 처리)
|
|
1975
|
-
*
|
|
1976
|
-
* 서버는 HTTP 200 + `success:false` + 개별 op `error` 로 부분 실패를 표현한다.
|
|
1977
|
-
* SDK 는 호출자가 silent success 로 오해하지 않도록 첫 실패 op 의 메시지로 throw 한다.
|
|
1978
962
|
*/
|
|
1979
|
-
batch(operations: BatchOperation[]): Promise<
|
|
963
|
+
batch(operations: BatchOperation[]): Promise<{
|
|
964
|
+
results: Record<string, unknown>[];
|
|
965
|
+
}>;
|
|
1980
966
|
/**
|
|
1981
967
|
* 트랜잭션 실행 (읽기 → 쓰기 ACID)
|
|
1982
|
-
*
|
|
1983
|
-
* 서버는 부분 실패가 없는 ACID 트랜잭션을 보장하지만, 검증/RLS/충돌은
|
|
1984
|
-
* `success:false` + `error` 로 알린다. SDK 는 silent success 회귀 방지 차원에서 throw.
|
|
1985
968
|
*/
|
|
1986
|
-
transaction(reads: TransactionRead[], writes: TransactionWrite[]): Promise<
|
|
969
|
+
transaction(reads: TransactionRead[], writes: TransactionWrite[]): Promise<{
|
|
970
|
+
results: Record<string, unknown>;
|
|
971
|
+
}>;
|
|
1987
972
|
/**
|
|
1988
973
|
* 데이터 조회 시 릴레이션 로딩 (JOIN)
|
|
1989
974
|
*/
|
|
@@ -2029,23 +1014,17 @@ declare class DatabaseAPI {
|
|
|
2029
1014
|
createGeoIndex(appId: string, tableId: string, data: CreateGeoIndexRequest): Promise<GeoIndex>;
|
|
2030
1015
|
deleteGeoIndex(appId: string, tableId: string, indexId: string): Promise<void>;
|
|
2031
1016
|
/**
|
|
2032
|
-
* 테이블 릴레이션 목록
|
|
2033
|
-
*
|
|
2034
|
-
* 서버 경로: `GET /v1/apps/:appID/databases/relations[?source_table=...]`
|
|
1017
|
+
* 테이블 릴레이션 목록 조회
|
|
2035
1018
|
*/
|
|
2036
|
-
listRelations(appId: string,
|
|
1019
|
+
listRelations(appId: string, tableId: string): Promise<TableRelation[]>;
|
|
2037
1020
|
/**
|
|
2038
|
-
* 릴레이션
|
|
2039
|
-
*
|
|
2040
|
-
* 서버 경로: `POST /v1/apps/:appID/databases/relations` — body 내 `source_table`/`target_table` 로 테이블 지정.
|
|
1021
|
+
* 릴레이션 생성
|
|
2041
1022
|
*/
|
|
2042
|
-
createRelation(appId: string, data: CreateRelationRequest): Promise<TableRelation>;
|
|
1023
|
+
createRelation(appId: string, tableId: string, data: CreateRelationRequest): Promise<TableRelation>;
|
|
2043
1024
|
/**
|
|
2044
|
-
* 릴레이션
|
|
2045
|
-
*
|
|
2046
|
-
* 서버 경로: `DELETE /v1/apps/:appID/databases/relations/:relationID`
|
|
1025
|
+
* 릴레이션 삭제
|
|
2047
1026
|
*/
|
|
2048
|
-
deleteRelation(appId: string,
|
|
1027
|
+
deleteRelation(appId: string, tableId: string, relationName: string): Promise<void>;
|
|
2049
1028
|
/**
|
|
2050
1029
|
* 트리거 목록 조회
|
|
2051
1030
|
*/
|
|
@@ -2108,26 +1087,14 @@ declare class DatabaseAPI {
|
|
|
2108
1087
|
* 데이터베이스 실시간 연결
|
|
2109
1088
|
* data-server의 WebSocket에 연결하여 데이터 변경을 실시간으로 수신합니다.
|
|
2110
1089
|
*
|
|
2111
|
-
* `accessToken` 은 두 종류를 모두 받습니다:
|
|
2112
|
-
* - 앱 멤버(AppMember) JWT — 자기 앱의 테이블을 구독
|
|
2113
|
-
* - cross-app OAuth access token — Provider 앱이 `database:read` scope 를 노출했을 때,
|
|
2114
|
-
* Consumer 가 Provider 앱의 테이블을 구독 (구독 대상 앱은 토큰 `aud` 로 결정되므로
|
|
2115
|
-
* Provider 의 publicKey 는 불필요). RLS 는 토큰 `end_user_id` 를 subject 로 평가합니다.
|
|
2116
|
-
*
|
|
2117
1090
|
* @example
|
|
2118
1091
|
* ```typescript
|
|
2119
|
-
* //
|
|
1092
|
+
* // 연결
|
|
2120
1093
|
* cb.database.connectRealtime({
|
|
2121
1094
|
* accessToken: 'your-jwt-token',
|
|
2122
1095
|
* dataServerUrl: 'https://data.connectbase.world'
|
|
2123
1096
|
* })
|
|
2124
1097
|
*
|
|
2125
|
-
* // cross-app: Provider 앱의 테이블 구독 (OAuth access token)
|
|
2126
|
-
* cb.database.connectRealtime({
|
|
2127
|
-
* accessToken: oauthAccessToken,
|
|
2128
|
-
* dataServerUrl: 'https://data.connectbase.world'
|
|
2129
|
-
* })
|
|
2130
|
-
*
|
|
2131
1098
|
* // 테이블 구독
|
|
2132
1099
|
* const sub = cb.database.subscribe('users', {
|
|
2133
1100
|
* onSnapshot: (docs, info) => {
|
|
@@ -2162,6 +1129,14 @@ declare class DatabaseAPI {
|
|
|
2162
1129
|
* @returns 구독 해제 가능한 객체
|
|
2163
1130
|
*/
|
|
2164
1131
|
subscribe(tableId: string, handlers: DatabaseRealtimeHandlers, options?: DatabaseSubscribeOptions): DatabaseRealtimeSubscription;
|
|
1132
|
+
/**
|
|
1133
|
+
* 프레즌스 상태 설정
|
|
1134
|
+
*/
|
|
1135
|
+
setPresence(status: string, device?: string, metadata?: Record<string, unknown>): void;
|
|
1136
|
+
/**
|
|
1137
|
+
* 프레즌스 구독 (다른 사용자의 온라인 상태 감시)
|
|
1138
|
+
*/
|
|
1139
|
+
subscribePresence(userIds: string[], onPresence: (states: Record<string, DatabasePresenceState>) => void): void;
|
|
2165
1140
|
/**
|
|
2166
1141
|
* 실시간 연결 상태 확인
|
|
2167
1142
|
*/
|
|
@@ -2391,28 +1366,10 @@ declare class StorageAPI {
|
|
|
2391
1366
|
* API Key 인증 시 /v1/public 접두사 반환
|
|
2392
1367
|
*/
|
|
2393
1368
|
private getPublicPrefix;
|
|
2394
|
-
/**
|
|
2395
|
-
* Presigned URL 로 직접 업로드. 호출 전에 URL 스킴(https)을 검증해
|
|
2396
|
-
* 서버 응답을 그대로 신뢰하는 SSRF/오용 경로를 차단.
|
|
2397
|
-
* 타임아웃과 외부 signal 을 모두 지원한다.
|
|
2398
|
-
*/
|
|
2399
|
-
private uploadToPresigned;
|
|
2400
1369
|
/**
|
|
2401
1370
|
* 파일 목록 조회
|
|
2402
|
-
*
|
|
2403
|
-
* @param storageId - 파일 스토리지 ID
|
|
2404
|
-
* @param parentId - 부모 폴더 ID (미지정 시 루트 폴더)
|
|
2405
|
-
*
|
|
2406
|
-
* @example
|
|
2407
|
-
* ```ts
|
|
2408
|
-
* // 루트 폴더의 파일 목록
|
|
2409
|
-
* const files = await cb.storage.getFiles('storage-id')
|
|
2410
|
-
*
|
|
2411
|
-
* // 특정 폴더의 하위 파일 목록
|
|
2412
|
-
* const subFiles = await cb.storage.getFiles('storage-id', 'folder-id')
|
|
2413
|
-
* ```
|
|
2414
1371
|
*/
|
|
2415
|
-
getFiles(storageId: string
|
|
1372
|
+
getFiles(storageId: string): Promise<FileItem[]>;
|
|
2416
1373
|
/**
|
|
2417
1374
|
* 파일 업로드 (Presigned URL 방식)
|
|
2418
1375
|
*
|
|
@@ -2440,14 +1397,10 @@ declare class StorageAPI {
|
|
|
2440
1397
|
deleteFile(storageId: string, fileId: string): Promise<void>;
|
|
2441
1398
|
/**
|
|
2442
1399
|
* 파일/폴더 이동
|
|
2443
|
-
*
|
|
2444
|
-
* Public Key 인증만으로는 이 엔드포인트가 노출되지 않습니다. JWT(콘솔 토큰)가 필요합니다.
|
|
2445
1400
|
*/
|
|
2446
1401
|
moveFile(storageId: string, fileId: string, data: MoveFileRequest): Promise<void>;
|
|
2447
1402
|
/**
|
|
2448
1403
|
* 파일/폴더 이름 변경
|
|
2449
|
-
*
|
|
2450
|
-
* Public Key 인증만으로는 이 엔드포인트가 노출되지 않습니다. JWT(콘솔 토큰)가 필요합니다.
|
|
2451
1404
|
*/
|
|
2452
1405
|
renameFile(storageId: string, fileId: string, data: RenameFileRequest): Promise<RenameFileResponse>;
|
|
2453
1406
|
/**
|
|
@@ -2571,15 +1524,15 @@ declare class StorageAPI {
|
|
|
2571
1524
|
}
|
|
2572
1525
|
|
|
2573
1526
|
/**
|
|
2574
|
-
*
|
|
1527
|
+
* API Key 관련 타입 정의
|
|
2575
1528
|
*/
|
|
2576
1529
|
/**
|
|
2577
|
-
*
|
|
1530
|
+
* API Key 아이템
|
|
2578
1531
|
*/
|
|
2579
|
-
interface
|
|
2580
|
-
/**
|
|
1532
|
+
interface ApiKeyItem {
|
|
1533
|
+
/** API Key ID */
|
|
2581
1534
|
id: string;
|
|
2582
|
-
/**
|
|
1535
|
+
/** API Key 이름 */
|
|
2583
1536
|
name: string;
|
|
2584
1537
|
/** 키 앞 12자리 (표시용) */
|
|
2585
1538
|
key_prefix: string;
|
|
@@ -2593,21 +1546,21 @@ interface PublicKeyItem {
|
|
|
2593
1546
|
created_at: string;
|
|
2594
1547
|
}
|
|
2595
1548
|
/**
|
|
2596
|
-
*
|
|
1549
|
+
* API Key 생성 요청
|
|
2597
1550
|
*/
|
|
2598
|
-
interface
|
|
2599
|
-
/**
|
|
1551
|
+
interface CreateApiKeyRequest {
|
|
1552
|
+
/** API Key 이름 (예: Production, Development) */
|
|
2600
1553
|
name: string;
|
|
2601
1554
|
/** 만료일 (옵션) */
|
|
2602
1555
|
expires_at?: string;
|
|
2603
1556
|
}
|
|
2604
1557
|
/**
|
|
2605
|
-
*
|
|
1558
|
+
* API Key 생성 응답 (전체 키는 이때만 반환됨)
|
|
2606
1559
|
*/
|
|
2607
|
-
interface
|
|
2608
|
-
/**
|
|
1560
|
+
interface CreateApiKeyResponse {
|
|
1561
|
+
/** API Key ID */
|
|
2609
1562
|
id: string;
|
|
2610
|
-
/**
|
|
1563
|
+
/** API Key 이름 */
|
|
2611
1564
|
name: string;
|
|
2612
1565
|
/** 전체 키 값 (생성 시에만 반환, 안전하게 보관 필요) */
|
|
2613
1566
|
key: string;
|
|
@@ -2621,24 +1574,24 @@ interface CreatePublicKeyResponse {
|
|
|
2621
1574
|
created_at: string;
|
|
2622
1575
|
}
|
|
2623
1576
|
/**
|
|
2624
|
-
*
|
|
1577
|
+
* API Key 목록 조회 응답
|
|
2625
1578
|
*/
|
|
2626
|
-
interface
|
|
2627
|
-
|
|
1579
|
+
interface FetchApiKeysResponse {
|
|
1580
|
+
api_keys: ApiKeyItem[];
|
|
2628
1581
|
}
|
|
2629
1582
|
/**
|
|
2630
|
-
*
|
|
1583
|
+
* API Key 수정 요청
|
|
2631
1584
|
*/
|
|
2632
|
-
interface
|
|
2633
|
-
/**
|
|
1585
|
+
interface UpdateApiKeyRequest {
|
|
1586
|
+
/** API Key 이름 변경 */
|
|
2634
1587
|
name?: string;
|
|
2635
1588
|
/** 활성화/비활성화 */
|
|
2636
1589
|
is_active?: boolean;
|
|
2637
1590
|
}
|
|
2638
1591
|
/**
|
|
2639
|
-
*
|
|
1592
|
+
* API Key 수정 응답
|
|
2640
1593
|
*/
|
|
2641
|
-
interface
|
|
1594
|
+
interface UpdateApiKeyResponse {
|
|
2642
1595
|
id: string;
|
|
2643
1596
|
name: string;
|
|
2644
1597
|
key_prefix: string;
|
|
@@ -2648,55 +1601,55 @@ interface UpdatePublicKeyResponse {
|
|
|
2648
1601
|
}
|
|
2649
1602
|
|
|
2650
1603
|
/**
|
|
2651
|
-
*
|
|
1604
|
+
* API Key 관리 API
|
|
2652
1605
|
*
|
|
2653
1606
|
* @example
|
|
2654
1607
|
* ```typescript
|
|
2655
|
-
* //
|
|
2656
|
-
* const keys = await cb.
|
|
1608
|
+
* // API Key 목록 조회
|
|
1609
|
+
* const keys = await cb.apiKey.getApiKeys('app-id')
|
|
2657
1610
|
*
|
|
2658
|
-
* // 새
|
|
2659
|
-
* const newKey = await cb.
|
|
1611
|
+
* // 새 API Key 생성
|
|
1612
|
+
* const newKey = await cb.apiKey.createApiKey('app-id', { name: 'Production' })
|
|
2660
1613
|
* console.log(newKey.key) // 전체 키 (이때만 볼 수 있음!)
|
|
2661
1614
|
*
|
|
2662
|
-
* //
|
|
2663
|
-
* await cb.
|
|
1615
|
+
* // API Key 비활성화
|
|
1616
|
+
* await cb.apiKey.updateApiKey('app-id', 'key-id', { is_active: false })
|
|
2664
1617
|
*
|
|
2665
|
-
* //
|
|
2666
|
-
* await cb.
|
|
1618
|
+
* // API Key 삭제
|
|
1619
|
+
* await cb.apiKey.deleteApiKey('app-id', 'key-id')
|
|
2667
1620
|
* ```
|
|
2668
1621
|
*/
|
|
2669
|
-
declare class
|
|
1622
|
+
declare class ApiKeyAPI {
|
|
2670
1623
|
private http;
|
|
2671
1624
|
constructor(http: HttpClient);
|
|
2672
1625
|
/**
|
|
2673
|
-
* 앱의
|
|
1626
|
+
* 앱의 API Key 목록을 조회합니다
|
|
2674
1627
|
* @param appId 앱 ID
|
|
2675
1628
|
*/
|
|
2676
|
-
|
|
1629
|
+
getApiKeys(appId: string): Promise<FetchApiKeysResponse>;
|
|
2677
1630
|
/**
|
|
2678
|
-
* 새
|
|
1631
|
+
* 새 API Key를 생성합니다
|
|
2679
1632
|
*
|
|
2680
1633
|
* **중요**: 반환되는 `key` 값은 이 응답에서만 볼 수 있습니다.
|
|
2681
1634
|
* 안전한 곳에 저장하세요.
|
|
2682
1635
|
*
|
|
2683
1636
|
* @param appId 앱 ID
|
|
2684
|
-
* @param data 생성할
|
|
1637
|
+
* @param data 생성할 API Key 정보
|
|
2685
1638
|
*/
|
|
2686
|
-
|
|
1639
|
+
createApiKey(appId: string, data: CreateApiKeyRequest): Promise<CreateApiKeyResponse>;
|
|
2687
1640
|
/**
|
|
2688
|
-
*
|
|
1641
|
+
* API Key를 수정합니다 (이름 변경, 활성화/비활성화)
|
|
2689
1642
|
* @param appId 앱 ID
|
|
2690
|
-
* @param keyId
|
|
1643
|
+
* @param keyId API Key ID
|
|
2691
1644
|
* @param data 수정할 정보
|
|
2692
1645
|
*/
|
|
2693
|
-
|
|
1646
|
+
updateApiKey(appId: string, keyId: string, data: UpdateApiKeyRequest): Promise<UpdateApiKeyResponse>;
|
|
2694
1647
|
/**
|
|
2695
|
-
*
|
|
1648
|
+
* API Key를 삭제합니다
|
|
2696
1649
|
* @param appId 앱 ID
|
|
2697
|
-
* @param keyId
|
|
1650
|
+
* @param keyId API Key ID
|
|
2698
1651
|
*/
|
|
2699
|
-
|
|
1652
|
+
deleteApiKey(appId: string, keyId: string): Promise<void>;
|
|
2700
1653
|
}
|
|
2701
1654
|
|
|
2702
1655
|
/**
|
|
@@ -2757,36 +1710,6 @@ declare class FunctionsAPI {
|
|
|
2757
1710
|
* ```
|
|
2758
1711
|
*/
|
|
2759
1712
|
invoke(functionId: string, payload?: Record<string, unknown>, timeout?: number): Promise<InvokeFunctionResponse>;
|
|
2760
|
-
/**
|
|
2761
|
-
* cross-app OAuth 액세스 토큰으로 다른 앱(Provider)의 함수를 실행합니다.
|
|
2762
|
-
*
|
|
2763
|
-
* Provider 앱이 OAuth Provider 로 `function:invoke` scope 를 노출하고, Consumer 앱이
|
|
2764
|
-
* cross-app OAuth 로 발급받은 access token 으로 Provider 의 함수를 호출하는 경로입니다.
|
|
2765
|
-
* 호출자 신원은 서버가 토큰에서 추출해 함수 런타임의 `ctx.memberId`(end-user) /
|
|
2766
|
-
* `ctx.callerAppId`(Consumer 앱) 로 전달하므로, 함수 핸들러가 호출자별 로직을 구현할 수 있습니다.
|
|
2767
|
-
*
|
|
2768
|
-
* 일반 `invoke()` 와 달리 SDK 클라이언트의 publicKey/멤버 토큰이 아니라 전달된
|
|
2769
|
-
* `accessToken` 만 `Authorization: Bearer` 로 사용합니다.
|
|
2770
|
-
*
|
|
2771
|
-
* @param providerAppId - 함수를 소유한 Provider 앱 ID (토큰 `aud` 의 `app:<id>` 와 일치해야 함)
|
|
2772
|
-
* @param functionId - 실행할 함수 ID
|
|
2773
|
-
* @param accessToken - cross-app OAuth access token
|
|
2774
|
-
* @param payload - 함수에 전달할 데이터 (선택)
|
|
2775
|
-
* @param timeout - 실행 타임아웃 (초, 선택)
|
|
2776
|
-
* @returns 함수 실행 결과
|
|
2777
|
-
*
|
|
2778
|
-
* @example
|
|
2779
|
-
* ```typescript
|
|
2780
|
-
* // Consumer 앱이 Provider(ai-tool)의 함수를 호출
|
|
2781
|
-
* const result = await cb.functions.invokeCrossApp(
|
|
2782
|
-
* 'provider-app-id',
|
|
2783
|
-
* 'models-generate-image',
|
|
2784
|
-
* oauthAccessToken,
|
|
2785
|
-
* { prompt: 'a cat' }
|
|
2786
|
-
* )
|
|
2787
|
-
* ```
|
|
2788
|
-
*/
|
|
2789
|
-
invokeCrossApp(providerAppId: string, functionId: string, accessToken: string, payload?: Record<string, unknown>, timeout?: number): Promise<InvokeFunctionResponse>;
|
|
2790
1713
|
/**
|
|
2791
1714
|
* 서버리스 함수 실행 (비동기 래퍼)
|
|
2792
1715
|
* 결과만 반환하고 메타데이터는 제외
|
|
@@ -2802,25 +1725,6 @@ declare class FunctionsAPI {
|
|
|
2802
1725
|
* ```
|
|
2803
1726
|
*/
|
|
2804
1727
|
call<T = unknown>(functionId: string, payload?: Record<string, unknown>): Promise<T>;
|
|
2805
|
-
/**
|
|
2806
|
-
* 함수의 raw HTTP webhook 수신용 공개 URL 을 반환합니다.
|
|
2807
|
-
*
|
|
2808
|
-
* 함수가 `http_trigger_enabled=true` 로 생성/수정되어야 동작합니다.
|
|
2809
|
-
* 이 URL 을 외부 SaaS (Discord Interactions, Stripe Webhooks, GitHub Webhooks,
|
|
2810
|
-
* Slack Events 등) 에 등록하면 raw HTTP 요청이 함수 핸들러에 그대로 전달됩니다.
|
|
2811
|
-
*
|
|
2812
|
-
* - body 는 wrap 없이 raw bytes 그대로 (Ed25519/HMAC 서명 검증 호환)
|
|
2813
|
-
* - 모든 헤더 forward (X-Signature-*, Stripe-Signature 등)
|
|
2814
|
-
* - 함수가 `{statusCode, headers, body}` 를 반환하면 그대로 HTTP 응답에 매핑
|
|
2815
|
-
*
|
|
2816
|
-
* @example
|
|
2817
|
-
* ```typescript
|
|
2818
|
-
* // Discord 봇 endpoint 등록용 URL
|
|
2819
|
-
* const url = cb.functions.getWebhookURL('function-id')
|
|
2820
|
-
* // → https://api.connectbase.world/v1/public/functions/<id>/webhook
|
|
2821
|
-
* ```
|
|
2822
|
-
*/
|
|
2823
|
-
getWebhookURL(functionId: string): string;
|
|
2824
1728
|
}
|
|
2825
1729
|
|
|
2826
1730
|
/**
|
|
@@ -2901,47 +1805,22 @@ interface ClientMessage {
|
|
|
2901
1805
|
/** 서버 -> 클라이언트 메시지 */
|
|
2902
1806
|
interface ServerMessage<T = unknown> {
|
|
2903
1807
|
category?: string;
|
|
2904
|
-
event: 'connected' | 'subscribed' | 'unsubscribed' | 'message' | 'sent' | 'result' | 'error' | 'pong' | 'history' | 'stream_token' | 'stream_done' | 'stream_error' | '
|
|
1808
|
+
event: 'connected' | 'subscribed' | 'unsubscribed' | 'message' | 'sent' | 'result' | 'error' | 'pong' | 'history' | 'stream_token' | 'stream_done' | 'stream_error' | 'read_receipt' | 'presence' | 'presence_status' | 'typing';
|
|
2905
1809
|
data?: T;
|
|
2906
1810
|
request_id?: string;
|
|
2907
1811
|
error?: string;
|
|
2908
1812
|
timestamp: number;
|
|
2909
1813
|
}
|
|
2910
|
-
/** AI 스트리밍
|
|
2911
|
-
interface StreamTextPart {
|
|
2912
|
-
type: 'text';
|
|
2913
|
-
text: string;
|
|
2914
|
-
}
|
|
2915
|
-
/** AI 스트리밍 메시지의 이미지 파트. URL 은 https://... 또는 data:image/...;base64,... */
|
|
2916
|
-
interface StreamImageURLPart {
|
|
2917
|
-
type: 'image_url';
|
|
2918
|
-
image_url: {
|
|
2919
|
-
url: string;
|
|
2920
|
-
/** OpenAI 전용 힌트 ('auto' | 'low' | 'high'). 다른 provider 는 무시. */
|
|
2921
|
-
detail?: 'auto' | 'low' | 'high';
|
|
2922
|
-
};
|
|
2923
|
-
}
|
|
2924
|
-
/** AI 스트리밍 메시지의 단일 content 파트. */
|
|
2925
|
-
type StreamContentPart = StreamTextPart | StreamImageURLPart;
|
|
2926
|
-
/**
|
|
2927
|
-
* AI 스트리밍 메시지.
|
|
2928
|
-
*
|
|
2929
|
-
* content 는 string (단일 텍스트) 또는 StreamContentPart[] (멀티모달) 를 받습니다.
|
|
2930
|
-
* 멀티모달 형식은 OpenAI Vision spec (https://platform.openai.com/docs/guides/vision)
|
|
2931
|
-
* 을 따르며, 서버가 각 provider 의 wire format 으로 변환:
|
|
2932
|
-
* - openai / openai_compatible (vLLM 등): content array 그대로 passthrough
|
|
2933
|
-
* - claude: data URI → base64 source, https URL → url source 의 image content block
|
|
2934
|
-
* - gemini: image URL fetch → base64 inline_data (Gemini API 가 외부 URL fetch 미지원)
|
|
2935
|
-
*/
|
|
1814
|
+
/** AI 스트리밍 메시지 */
|
|
2936
1815
|
interface StreamMessage {
|
|
2937
1816
|
role: 'user' | 'assistant' | 'system';
|
|
2938
|
-
content: string
|
|
1817
|
+
content: string;
|
|
2939
1818
|
}
|
|
2940
1819
|
/** AI 스트리밍 요청 옵션 */
|
|
2941
1820
|
interface StreamOptions {
|
|
2942
|
-
/** AI 프로바이더 (
|
|
2943
|
-
provider?: 'gemini' | 'openai' | 'claude'
|
|
2944
|
-
/** 모델명 (
|
|
1821
|
+
/** AI 프로바이더 (기본: gemini) */
|
|
1822
|
+
provider?: 'gemini' | 'openai' | 'claude';
|
|
1823
|
+
/** 모델명 (기본: gemini-2.5-flash) */
|
|
2945
1824
|
model?: string;
|
|
2946
1825
|
/** 시스템 프롬프트 */
|
|
2947
1826
|
system?: string;
|
|
@@ -2953,8 +1832,6 @@ interface StreamOptions {
|
|
|
2953
1832
|
sessionId?: string;
|
|
2954
1833
|
/** 사용자 정의 메타데이터 */
|
|
2955
1834
|
metadata?: Record<string, unknown>;
|
|
2956
|
-
/** MCP 그룹 슬러그 (AI Agent 모드 — 등록된 MCP 서버의 도구를 AI에 제공) */
|
|
2957
|
-
mcpGroup?: string;
|
|
2958
1835
|
}
|
|
2959
1836
|
/** AI 스트리밍 토큰 콜백 */
|
|
2960
1837
|
type StreamTokenCallback = (token: string, index: number) => void;
|
|
@@ -2970,19 +1847,11 @@ interface StreamDoneData {
|
|
|
2970
1847
|
type StreamDoneCallback = (result: StreamDoneData) => void;
|
|
2971
1848
|
/** AI 스트리밍 에러 콜백 */
|
|
2972
1849
|
type StreamErrorCallback = (error: Error) => void;
|
|
2973
|
-
/** AI 도구 호출 콜백 */
|
|
2974
|
-
type StreamToolCallCallback = (toolName: string, args: Record<string, unknown>, index: number) => void;
|
|
2975
|
-
/** AI 도구 실행 완료 콜백 */
|
|
2976
|
-
type StreamToolResultCallback = (toolName: string, success: boolean, durationMs: number, index: number) => void;
|
|
2977
1850
|
/** AI 스트리밍 핸들러 */
|
|
2978
1851
|
interface StreamHandlers {
|
|
2979
1852
|
onToken?: StreamTokenCallback;
|
|
2980
1853
|
onDone?: StreamDoneCallback;
|
|
2981
1854
|
onError?: StreamErrorCallback;
|
|
2982
|
-
/** MCP 도구 호출 시 콜백 (AI Agent 모드) */
|
|
2983
|
-
onToolCall?: StreamToolCallCallback;
|
|
2984
|
-
/** MCP 도구 실행 완료 시 콜백 (AI Agent 모드) */
|
|
2985
|
-
onToolResult?: StreamToolResultCallback;
|
|
2986
1855
|
}
|
|
2987
1856
|
/** AI 스트리밍 세션 */
|
|
2988
1857
|
interface StreamSession {
|
|
@@ -3342,12 +2211,6 @@ declare class RealtimeAPI {
|
|
|
3342
2211
|
onReadReceipt(category: string, handler: ReadReceiptHandler): () => void;
|
|
3343
2212
|
private doConnect;
|
|
3344
2213
|
private log;
|
|
3345
|
-
/**
|
|
3346
|
-
* 에러 로그. `options.debug` 가 true 일 때만 console 에 출력.
|
|
3347
|
-
* 운영 환경에서는 소비자 애플리케이션의 `ConnectBase({ onError })` 또는
|
|
3348
|
-
* `cb.errorTracker` 로 전달하는 것을 권장하므로 SDK 자체 console 출력은 opt-in.
|
|
3349
|
-
*/
|
|
3350
|
-
private logError;
|
|
3351
2214
|
private handleServerMessage;
|
|
3352
2215
|
private handleDisconnect;
|
|
3353
2216
|
/**
|
|
@@ -3708,7 +2571,7 @@ declare class ErrorTrackerAPI {
|
|
|
3708
2571
|
/**
|
|
3709
2572
|
* OAuth 프로바이더 타입
|
|
3710
2573
|
*/
|
|
3711
|
-
type OAuthProvider = 'google' | 'kakao' | 'naver' | '
|
|
2574
|
+
type OAuthProvider = 'google' | 'kakao' | 'naver' | 'github' | 'discord' | 'apple';
|
|
3712
2575
|
/**
|
|
3713
2576
|
* 활성화된 OAuth 프로바이더 정보
|
|
3714
2577
|
*/
|
|
@@ -3730,19 +2593,29 @@ interface GetAuthorizationURLResponse {
|
|
|
3730
2593
|
}
|
|
3731
2594
|
/**
|
|
3732
2595
|
* OAuth 콜백 응답
|
|
3733
|
-
*
|
|
3734
|
-
* `email` 은 1.10 부터 추가된 선택적 필드. Apple private relay 또는 이메일 권한 미동의
|
|
3735
|
-
* 시 빈 문자열 / undefined 일 수 있다. 값이 있으면 첫 로그인 시점에 이메일을 확보할 수 있어
|
|
3736
|
-
* 별도 `getMember()` 호출이 불필요하다.
|
|
3737
2596
|
*/
|
|
3738
2597
|
interface OAuthCallbackResponse {
|
|
3739
2598
|
member_id: string;
|
|
3740
2599
|
access_token: string;
|
|
3741
2600
|
refresh_token: string;
|
|
3742
2601
|
is_new_member: boolean;
|
|
3743
|
-
email?: string;
|
|
3744
2602
|
}
|
|
3745
2603
|
|
|
2604
|
+
/**
|
|
2605
|
+
* 3rd-party 인앱 브라우저(카카오톡, 라인, 인스타그램, 페이스북 등) 감지
|
|
2606
|
+
* 구글은 이런 환경에서 OAuth를 차단(disallowed_useragent)하므로 별도 처리 필요
|
|
2607
|
+
*/
|
|
2608
|
+
declare function detectInAppBrowser(): {
|
|
2609
|
+
type: 'kakaotalk' | 'line' | 'instagram' | 'facebook' | 'naverapp' | 'wechat' | 'other';
|
|
2610
|
+
ua: string;
|
|
2611
|
+
} | null;
|
|
2612
|
+
/**
|
|
2613
|
+
* 3rd-party 인앱 브라우저에서 현재 URL을 외부(시스템) 브라우저로 강제로 여는 방법 제공
|
|
2614
|
+
* - 카카오톡: kakaotalk://web/openExternal?url=...
|
|
2615
|
+
* - 라인: line://nv/openURL?url=...
|
|
2616
|
+
* - 그 외: 사용자에게 안내 메시지 표시 권장
|
|
2617
|
+
*/
|
|
2618
|
+
declare function escapeToExternalBrowser(currentUrl?: string): boolean;
|
|
3746
2619
|
/**
|
|
3747
2620
|
* OAuth API
|
|
3748
2621
|
* 소셜 로그인 (Google, Naver, GitHub, Discord)
|
|
@@ -3781,7 +2654,7 @@ declare class OAuthAPI {
|
|
|
3781
2654
|
* @example
|
|
3782
2655
|
* ```typescript
|
|
3783
2656
|
* // callback 페이지에서
|
|
3784
|
-
* const result =
|
|
2657
|
+
* const result = cb.oauth.getCallbackResult()
|
|
3785
2658
|
* if (result) {
|
|
3786
2659
|
* if (result.error) {
|
|
3787
2660
|
* console.error('로그인 실패:', result.error)
|
|
@@ -3824,64 +2697,30 @@ declare class OAuthAPI {
|
|
|
3824
2697
|
* 중앙 콜백 방식에서 리다이렉트 후 URL 파라미터에서 결과를 추출합니다.
|
|
3825
2698
|
* 토큰이 있으면 자동으로 저장됩니다.
|
|
3826
2699
|
*
|
|
3827
|
-
* 본 메서드는 `Promise` 를 반환한다. 토큰 저장 직후 `cb_member_refresh_token`
|
|
3828
|
-
* cookie 부트스트랩(`/v1/auth/re-issue` 1회)을 *await* 하기 위함이다. 표준 예제
|
|
3829
|
-
* 코드는 결과를 await 한 다음 `window.location.href='/'` 로 이동하므로, cookie 가
|
|
3830
|
-
* 브라우저에 안전하게 저장된 뒤 페이지가 전환된다.
|
|
3831
|
-
*
|
|
3832
|
-
* 이전(3.22.x) 의 fire-and-forget 부트스트랩은 모바일/느린 네트워크에서 navigation
|
|
3833
|
-
* 이 fetch 보다 먼저 발화해 cookie 가 발급되지 않고, 새 페이지 진입 시 cookie
|
|
3834
|
-
* 없는 상태로 `getMe()` 가 401 으로 떨어지는 회귀가 있었다 (platform-issue
|
|
3835
|
-
* 019e638d, 2026-05-26).
|
|
3836
|
-
*
|
|
3837
2700
|
* @returns OAuth 결과 (토큰, member_id 등) 또는 null
|
|
3838
2701
|
*
|
|
3839
2702
|
* @example
|
|
3840
2703
|
* ```typescript
|
|
3841
2704
|
* // callback 페이지에서
|
|
3842
|
-
* const result =
|
|
2705
|
+
* const result = cb.oauth.getCallbackResult()
|
|
3843
2706
|
* if (result) {
|
|
3844
2707
|
* if (result.error) {
|
|
3845
2708
|
* alert('로그인 실패: ' + result.error)
|
|
3846
2709
|
* } else {
|
|
2710
|
+
* console.log('로그인 성공:', result.member_id)
|
|
3847
2711
|
* window.location.href = '/'
|
|
3848
2712
|
* }
|
|
3849
2713
|
* }
|
|
3850
2714
|
* ```
|
|
3851
2715
|
*/
|
|
3852
|
-
getCallbackResult():
|
|
2716
|
+
getCallbackResult(): {
|
|
3853
2717
|
access_token?: string;
|
|
3854
2718
|
refresh_token?: string;
|
|
3855
2719
|
member_id?: string;
|
|
3856
2720
|
is_new_member?: boolean;
|
|
3857
|
-
email?: string;
|
|
3858
2721
|
state?: string;
|
|
3859
2722
|
error?: string;
|
|
3860
|
-
} | null
|
|
3861
|
-
/**
|
|
3862
|
-
* 콜백 URL 에서 1회용 `code` 를 토큰으로 교환합니다 (`OAUTH_CODE_ONLY` 서버 모드용).
|
|
3863
|
-
*
|
|
3864
|
-
* 서버가 `OAUTH_CODE_ONLY=true` 모드면 리다이렉트 URL 에 토큰 대신 `code` 만 포함됩니다.
|
|
3865
|
-
* 이 메서드는 code 를 `POST /v1/auth/oauth/exchange` 로 교환하고 토큰을 자동 저장합니다.
|
|
3866
|
-
*
|
|
3867
|
-
* 권장 호출 순서:
|
|
3868
|
-
* 1) `cb.oauth.exchangeCodeFromCallback()` 먼저 — code-only 모드면 성공
|
|
3869
|
-
* 2) null 반환 시 `cb.oauth.getCallbackResult()` 폴백 (legacy 토큰-in-URL 모드)
|
|
3870
|
-
*
|
|
3871
|
-
* @example
|
|
3872
|
-
* ```typescript
|
|
3873
|
-
* const result = await cb.oauth.exchangeCodeFromCallback()
|
|
3874
|
-
* ?? cb.oauth.getCallbackResult()
|
|
3875
|
-
* ```
|
|
3876
|
-
*/
|
|
3877
|
-
exchangeCodeFromCallback(): Promise<{
|
|
3878
|
-
access_token: string;
|
|
3879
|
-
refresh_token: string;
|
|
3880
|
-
member_id: string;
|
|
3881
|
-
is_new_member: boolean;
|
|
3882
|
-
email?: string;
|
|
3883
|
-
state?: string;
|
|
3884
|
-
} | null>;
|
|
2723
|
+
} | null;
|
|
3885
2724
|
}
|
|
3886
2725
|
|
|
3887
2726
|
type PaymentProvider = 'toss' | 'stripe';
|
|
@@ -3908,25 +2747,6 @@ interface PreparePaymentResponse {
|
|
|
3908
2747
|
stripe_client_secret?: string;
|
|
3909
2748
|
stripe_publishable_key?: string;
|
|
3910
2749
|
}
|
|
3911
|
-
interface CreateCheckoutSessionRequest {
|
|
3912
|
-
amount: number;
|
|
3913
|
-
currency: string;
|
|
3914
|
-
product_name: string;
|
|
3915
|
-
success_url: string;
|
|
3916
|
-
cancel_url: string;
|
|
3917
|
-
order_id?: string;
|
|
3918
|
-
customer_email?: string;
|
|
3919
|
-
customer_name?: string;
|
|
3920
|
-
metadata?: Record<string, unknown>;
|
|
3921
|
-
}
|
|
3922
|
-
interface CreateCheckoutSessionResponse {
|
|
3923
|
-
payment_id: string;
|
|
3924
|
-
order_id: string;
|
|
3925
|
-
amount: number;
|
|
3926
|
-
currency: string;
|
|
3927
|
-
session_id: string;
|
|
3928
|
-
session_url: string;
|
|
3929
|
-
}
|
|
3930
2750
|
interface ConfirmPaymentRequest {
|
|
3931
2751
|
payment_key: string;
|
|
3932
2752
|
order_id: string;
|
|
@@ -3986,69 +2806,43 @@ declare class PaymentAPI {
|
|
|
3986
2806
|
*/
|
|
3987
2807
|
private getPublicPrefix;
|
|
3988
2808
|
/**
|
|
3989
|
-
* 결제 준비
|
|
3990
|
-
* 토스 결제 위젯에 필요한 정보를 반환합니다.
|
|
3991
|
-
*
|
|
3992
|
-
* @param data - 결제 준비 정보 (금액, 상품명, 고객 정보 등)
|
|
3993
|
-
* @returns 토스 클라이언트 키, 고객 키, 성공/실패 URL 등
|
|
3994
|
-
*
|
|
3995
|
-
* @example
|
|
3996
|
-
* ```typescript
|
|
3997
|
-
* const result = await cb.payment.prepare({
|
|
3998
|
-
* amount: 10000,
|
|
3999
|
-
* order_name: '프리미엄 1개월',
|
|
4000
|
-
* customer_email: 'test@example.com',
|
|
4001
|
-
* customer_name: '홍길동'
|
|
4002
|
-
* })
|
|
4003
|
-
*
|
|
4004
|
-
* // Toss V2 결제 플로우
|
|
4005
|
-
* if (result.payment_provider === 'toss') {
|
|
4006
|
-
* const tossPayments = TossPayments(result.toss_client_key)
|
|
4007
|
-
* const payment = tossPayments.payment({ customerKey: result.customer_key })
|
|
4008
|
-
* await payment.requestPayment({
|
|
4009
|
-
* method: 'CARD',
|
|
4010
|
-
* amount: { currency: 'KRW', value: result.amount },
|
|
4011
|
-
* orderId: result.order_id,
|
|
4012
|
-
* orderName: result.order_name,
|
|
4013
|
-
* successUrl: result.success_url,
|
|
4014
|
-
* failUrl: result.fail_url,
|
|
4015
|
-
* })
|
|
4016
|
-
* }
|
|
4017
|
-
*
|
|
4018
|
-
* // Stripe 결제 플로우
|
|
4019
|
-
* if (result.payment_provider === 'stripe') {
|
|
4020
|
-
* const stripe = await loadStripe(result.stripe_publishable_key)
|
|
4021
|
-
* const elements = stripe.elements({ clientSecret: result.stripe_client_secret })
|
|
4022
|
-
* // Mount PaymentElement, then:
|
|
4023
|
-
* // stripe.confirmPayment({ elements, redirect: 'if_required' })
|
|
4024
|
-
* }
|
|
4025
|
-
* ```
|
|
4026
|
-
*/
|
|
4027
|
-
prepare(data: PreparePaymentRequest): Promise<PreparePaymentResponse>;
|
|
4028
|
-
/**
|
|
4029
|
-
* Stripe-hosted 결제 페이지 세션 생성 (client_secret 미노출 플로우).
|
|
4030
|
-
*
|
|
4031
|
-
* Elements 플로우(`prepare`) 대신 Stripe-hosted Checkout 페이지로 리다이렉트하고 싶을 때 사용.
|
|
4032
|
-
* 응답에 `session_url` 이 포함되며, 브라우저를 해당 URL 로 이동시키면 Stripe 가 카드 입력·결제를 처리한 뒤
|
|
4033
|
-
* `success_url` / `cancel_url` 로 복귀한다. `client_secret` 은 서버·클라이언트 어디에도 노출되지 않는다.
|
|
2809
|
+
* 결제 준비
|
|
2810
|
+
* 토스 결제 위젯에 필요한 정보를 반환합니다.
|
|
4034
2811
|
*
|
|
4035
|
-
* @param data - 결제
|
|
4036
|
-
* @returns
|
|
2812
|
+
* @param data - 결제 준비 정보 (금액, 상품명, 고객 정보 등)
|
|
2813
|
+
* @returns 토스 클라이언트 키, 고객 키, 성공/실패 URL 등
|
|
4037
2814
|
*
|
|
4038
2815
|
* @example
|
|
4039
2816
|
* ```typescript
|
|
4040
|
-
* const
|
|
4041
|
-
*
|
|
4042
|
-
*
|
|
4043
|
-
*
|
|
4044
|
-
*
|
|
4045
|
-
*
|
|
4046
|
-
*
|
|
2817
|
+
* const prepareResult = await client.payment.prepare({
|
|
2818
|
+
* amount: 10000,
|
|
2819
|
+
* order_name: '테스트 상품',
|
|
2820
|
+
* customer_email: 'test@example.com',
|
|
2821
|
+
* customer_name: '홍길동'
|
|
2822
|
+
* })
|
|
2823
|
+
*
|
|
2824
|
+
* // 토스 결제 위젯 초기화
|
|
2825
|
+
* const tossPayments = TossPayments(prepareResult.toss_client_key)
|
|
2826
|
+
* await tossPayments.requestPayment('카드', {
|
|
2827
|
+
* amount: prepareResult.amount,
|
|
2828
|
+
* orderId: prepareResult.order_id,
|
|
2829
|
+
* orderName: prepareResult.order_name,
|
|
2830
|
+
* customerKey: prepareResult.customer_key,
|
|
2831
|
+
* successUrl: prepareResult.success_url,
|
|
2832
|
+
* failUrl: prepareResult.fail_url
|
|
4047
2833
|
* })
|
|
4048
|
-
*
|
|
2834
|
+
*
|
|
2835
|
+
* // Stripe 결제 플로우:
|
|
2836
|
+
* // const result = await client.payment.prepare({ amount: 1000, order_name: 'Product' })
|
|
2837
|
+
* // if (result.payment_provider === 'stripe') {
|
|
2838
|
+
* // const stripe = await loadStripe(result.stripe_publishable_key)
|
|
2839
|
+
* // const elements = stripe.elements({ clientSecret: result.stripe_client_secret })
|
|
2840
|
+
* // // Mount PaymentElement, then:
|
|
2841
|
+
* // // stripe.confirmPayment({ elements, redirect: 'if_required' })
|
|
2842
|
+
* // }
|
|
4049
2843
|
* ```
|
|
4050
2844
|
*/
|
|
4051
|
-
|
|
2845
|
+
prepare(data: PreparePaymentRequest): Promise<PreparePaymentResponse>;
|
|
4052
2846
|
/**
|
|
4053
2847
|
* 결제 승인
|
|
4054
2848
|
* 토스에서 결제 완료 후 콜백으로 받은 정보로 결제를 최종 승인합니다.
|
|
@@ -4603,7 +3397,7 @@ declare class SubscriptionAPI {
|
|
|
4603
3397
|
* order_name: '추가 결제'
|
|
4604
3398
|
* })
|
|
4605
3399
|
*
|
|
4606
|
-
* if (result.status === '
|
|
3400
|
+
* if (result.status === 'DONE') {
|
|
4607
3401
|
* console.log('결제 완료!')
|
|
4608
3402
|
* }
|
|
4609
3403
|
* ```
|
|
@@ -4667,35 +3461,6 @@ interface WebPushSubscription {
|
|
|
4667
3461
|
};
|
|
4668
3462
|
}
|
|
4669
3463
|
|
|
4670
|
-
/**
|
|
4671
|
-
* `cb.push.sendToMembers` 페이로드. 백엔드 `dto.SendPushRequest` 의 멤버 발송 케이스
|
|
4672
|
-
* 에 매핑되며, target_type / target_member_ids 는 SDK 가 자동 채운다.
|
|
4673
|
-
*/
|
|
4674
|
-
interface SendToMembersPayload {
|
|
4675
|
-
title: string;
|
|
4676
|
-
body: string;
|
|
4677
|
-
imageUrl?: string;
|
|
4678
|
-
data?: Record<string, unknown>;
|
|
4679
|
-
/** 'ios' | 'android' | 'web' 중 선택. 빈 배열/미지정 시 전체 플랫폼 발송. */
|
|
4680
|
-
platforms?: Array<'ios' | 'android' | 'web'>;
|
|
4681
|
-
/** TTL(초). 기본 86400 (24h). */
|
|
4682
|
-
ttlSeconds?: number;
|
|
4683
|
-
priority?: 'normal' | 'high';
|
|
4684
|
-
clickAction?: string;
|
|
4685
|
-
/** ISO8601 형식 예약 발송 시각. 미지정 시 즉시 발송. */
|
|
4686
|
-
scheduledAt?: string;
|
|
4687
|
-
}
|
|
4688
|
-
/**
|
|
4689
|
-
* 발송 결과. 백엔드 `dto.SendResultResponse` 와 1:1 매핑.
|
|
4690
|
-
*/
|
|
4691
|
-
interface SendPushResult {
|
|
4692
|
-
message_id: string;
|
|
4693
|
-
total_target: number;
|
|
4694
|
-
sent_count: number;
|
|
4695
|
-
failed_count: number;
|
|
4696
|
-
status: string;
|
|
4697
|
-
error_message?: string;
|
|
4698
|
-
}
|
|
4699
3464
|
/**
|
|
4700
3465
|
* 푸시 알림 API
|
|
4701
3466
|
*
|
|
@@ -4708,8 +3473,8 @@ interface SendPushResult {
|
|
|
4708
3473
|
* device_name: 'Galaxy S24',
|
|
4709
3474
|
* })
|
|
4710
3475
|
*
|
|
4711
|
-
* // 토픽 구독
|
|
4712
|
-
* await cb.push.subscribeTopic(
|
|
3476
|
+
* // 토픽 구독
|
|
3477
|
+
* await cb.push.subscribeTopic('announcements')
|
|
4713
3478
|
*
|
|
4714
3479
|
* // Web Push 등록 (브라우저)
|
|
4715
3480
|
* const vapidKey = await cb.push.getVAPIDPublicKey()
|
|
@@ -4757,38 +3522,52 @@ declare class PushAPI {
|
|
|
4757
3522
|
/**
|
|
4758
3523
|
* 디바이스 등록 해제
|
|
4759
3524
|
*
|
|
4760
|
-
* @param
|
|
3525
|
+
* @param deviceId 디바이스 ID
|
|
4761
3526
|
*
|
|
4762
3527
|
* @example
|
|
4763
3528
|
* ```typescript
|
|
4764
|
-
* await cb.push.unregisterDevice('
|
|
3529
|
+
* await cb.push.unregisterDevice('device-id-here')
|
|
4765
3530
|
* ```
|
|
4766
3531
|
*/
|
|
4767
|
-
unregisterDevice(
|
|
3532
|
+
unregisterDevice(deviceId: string): Promise<void>;
|
|
3533
|
+
/**
|
|
3534
|
+
* 현재 등록된 디바이스 목록 조회
|
|
3535
|
+
*
|
|
3536
|
+
* @returns 디바이스 목록
|
|
3537
|
+
*/
|
|
3538
|
+
getDevices(): Promise<DeviceInfo[]>;
|
|
4768
3539
|
/**
|
|
4769
3540
|
* 토픽 구독
|
|
4770
3541
|
*
|
|
4771
|
-
* @param deviceToken 디바이스 토큰
|
|
4772
3542
|
* @param topicName 토픽 이름
|
|
4773
3543
|
*
|
|
4774
3544
|
* @example
|
|
4775
3545
|
* ```typescript
|
|
4776
|
-
*
|
|
3546
|
+
* // 공지사항 토픽 구독
|
|
3547
|
+
* await cb.push.subscribeTopic('announcements')
|
|
3548
|
+
*
|
|
3549
|
+
* // 마케팅 토픽 구독
|
|
3550
|
+
* await cb.push.subscribeTopic('marketing')
|
|
4777
3551
|
* ```
|
|
4778
3552
|
*/
|
|
4779
|
-
subscribeTopic(
|
|
3553
|
+
subscribeTopic(topicName: string): Promise<void>;
|
|
4780
3554
|
/**
|
|
4781
3555
|
* 토픽 구독 해제
|
|
4782
3556
|
*
|
|
4783
|
-
* @param deviceToken 디바이스 토큰
|
|
4784
3557
|
* @param topicName 토픽 이름
|
|
4785
3558
|
*
|
|
4786
3559
|
* @example
|
|
4787
3560
|
* ```typescript
|
|
4788
|
-
* await cb.push.unsubscribeTopic('
|
|
3561
|
+
* await cb.push.unsubscribeTopic('marketing')
|
|
4789
3562
|
* ```
|
|
4790
3563
|
*/
|
|
4791
|
-
unsubscribeTopic(
|
|
3564
|
+
unsubscribeTopic(topicName: string): Promise<void>;
|
|
3565
|
+
/**
|
|
3566
|
+
* 구독 중인 토픽 목록 조회
|
|
3567
|
+
*
|
|
3568
|
+
* @returns 구독 중인 토픽 이름 목록
|
|
3569
|
+
*/
|
|
3570
|
+
getSubscribedTopics(): Promise<string[]>;
|
|
4792
3571
|
/**
|
|
4793
3572
|
* VAPID Public Key 조회 (Web Push용)
|
|
4794
3573
|
*
|
|
@@ -4830,33 +3609,8 @@ declare class PushAPI {
|
|
|
4830
3609
|
registerWebPush(subscription: PushSubscription | WebPushSubscription): Promise<DeviceInfo>;
|
|
4831
3610
|
/**
|
|
4832
3611
|
* Web Push 구독 해제
|
|
4833
|
-
*
|
|
4834
|
-
* @param deviceToken Web Push endpoint URL (등록 시 사용한 endpoint)
|
|
4835
3612
|
*/
|
|
4836
|
-
unregisterWebPush(
|
|
4837
|
-
/**
|
|
4838
|
-
* 회원 ID 목록으로 푸시 발송 — Functions / cb_sk_ 인증 환경 전용.
|
|
4839
|
-
*
|
|
4840
|
-
* 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT 또는 User Secret Key
|
|
4841
|
-
* (`cb_sk_`) 만 받는다. 브라우저 SDK 의 Public Key(`cb_pk_`) 인스턴스에서는 호출
|
|
4842
|
-
* 자체가 차단되며, 권한 누설을 막기 위해 명확한 에러를 던진다.
|
|
4843
|
-
*
|
|
4844
|
-
* @param appId 발송 대상 앱 ID (cb_sk_ 환경은 user 단위 권한이므로 명시 전달).
|
|
4845
|
-
* @param memberIds 받는 회원 ID 배열 (UUID).
|
|
4846
|
-
* @param payload 푸시 내용/옵션.
|
|
4847
|
-
*
|
|
4848
|
-
* @example
|
|
4849
|
-
* ```ts
|
|
4850
|
-
* // ConnectBase Function (Node.js, secrets.CB_SECRET_KEY 주입)
|
|
4851
|
-
* const result = await cb.push.sendToMembers(APP_ID, [memberId], {
|
|
4852
|
-
* title: '새 알림',
|
|
4853
|
-
* body: '확인해보세요',
|
|
4854
|
-
* data: { route: '/notifications' },
|
|
4855
|
-
* })
|
|
4856
|
-
* console.log(result.message_id, result.sent_count)
|
|
4857
|
-
* ```
|
|
4858
|
-
*/
|
|
4859
|
-
sendToMembers(appId: string, memberIds: string[], payload: SendToMembersPayload): Promise<SendPushResult>;
|
|
3613
|
+
unregisterWebPush(): Promise<void>;
|
|
4860
3614
|
/**
|
|
4861
3615
|
* 브라우저 고유 ID 생성 (localStorage에 저장)
|
|
4862
3616
|
*/
|
|
@@ -5093,62 +3847,6 @@ interface ChannelMembership {
|
|
|
5093
3847
|
started_at: string;
|
|
5094
3848
|
expires_at?: string;
|
|
5095
3849
|
}
|
|
5096
|
-
interface VideoStorage {
|
|
5097
|
-
id: string;
|
|
5098
|
-
app_id: string;
|
|
5099
|
-
name: string;
|
|
5100
|
-
description: string;
|
|
5101
|
-
current_size: number;
|
|
5102
|
-
video_count: number;
|
|
5103
|
-
is_public: boolean;
|
|
5104
|
-
allow_server_to_server: boolean;
|
|
5105
|
-
allowed_origins: string[];
|
|
5106
|
-
strict_referer_check: boolean;
|
|
5107
|
-
cdn_provider: string;
|
|
5108
|
-
cdn_config: Record<string, unknown>;
|
|
5109
|
-
default_qualities: string[];
|
|
5110
|
-
hls_encryption_enabled: boolean;
|
|
5111
|
-
token_expiry_hours: number;
|
|
5112
|
-
created_at: string;
|
|
5113
|
-
updated_at: string;
|
|
5114
|
-
}
|
|
5115
|
-
interface CreateVideoStorageRequest {
|
|
5116
|
-
name: string;
|
|
5117
|
-
description?: string;
|
|
5118
|
-
is_public?: boolean;
|
|
5119
|
-
allow_server_to_server?: boolean;
|
|
5120
|
-
allowed_origins?: string[];
|
|
5121
|
-
strict_referer_check?: boolean;
|
|
5122
|
-
cdn_provider?: string;
|
|
5123
|
-
cdn_config?: Record<string, unknown>;
|
|
5124
|
-
default_qualities?: string[];
|
|
5125
|
-
hls_encryption_enabled?: boolean;
|
|
5126
|
-
token_expiry_hours?: number;
|
|
5127
|
-
}
|
|
5128
|
-
interface UpdateVideoStorageRequest {
|
|
5129
|
-
name?: string;
|
|
5130
|
-
description?: string;
|
|
5131
|
-
is_public?: boolean;
|
|
5132
|
-
allow_server_to_server?: boolean;
|
|
5133
|
-
allowed_origins?: string[];
|
|
5134
|
-
strict_referer_check?: boolean;
|
|
5135
|
-
cdn_provider?: string;
|
|
5136
|
-
cdn_config?: Record<string, unknown>;
|
|
5137
|
-
default_qualities?: string[];
|
|
5138
|
-
hls_encryption_enabled?: boolean;
|
|
5139
|
-
token_expiry_hours?: number;
|
|
5140
|
-
}
|
|
5141
|
-
interface VideoStorageListResponse {
|
|
5142
|
-
storage_videos: VideoStorage[];
|
|
5143
|
-
total_count: number;
|
|
5144
|
-
}
|
|
5145
|
-
interface StorageUploadOptions {
|
|
5146
|
-
title: string;
|
|
5147
|
-
description?: string;
|
|
5148
|
-
visibility?: VideoVisibility;
|
|
5149
|
-
tags?: string[];
|
|
5150
|
-
onProgress?: (progress: UploadProgress) => void;
|
|
5151
|
-
}
|
|
5152
3850
|
interface SuperChat {
|
|
5153
3851
|
id: string;
|
|
5154
3852
|
video_id: string;
|
|
@@ -5190,29 +3888,7 @@ declare class VideoAPI {
|
|
|
5190
3888
|
*/
|
|
5191
3889
|
waitForReady(videoId: string, options?: WaitOptions): Promise<Video>;
|
|
5192
3890
|
/**
|
|
5193
|
-
*
|
|
5194
|
-
*
|
|
5195
|
-
* 필터링/페이지네이션 옵션을 조합해 조건에 맞는 영상들을 반환한다.
|
|
5196
|
-
* API Key(publicKey) 또는 JWT 인증이 모두 지원되며, publicKey 로는 공개 영상만 노출된다.
|
|
5197
|
-
*
|
|
5198
|
-
* @param options - 필터/페이지네이션 옵션
|
|
5199
|
-
* @param options.status - `uploading` | `processing` | `ready` | `failed`
|
|
5200
|
-
* @param options.visibility - `public` | `unlisted` | `private` | `members`
|
|
5201
|
-
* @param options.search - 제목 부분 일치 검색
|
|
5202
|
-
* @param options.channel_id - 특정 채널로 한정
|
|
5203
|
-
* @param options.page - 1 부터 시작
|
|
5204
|
-
* @param options.limit - 기본 20, 최대 100
|
|
5205
|
-
* @returns `videos` 배열과 `total` 카운트를 포함하는 응답
|
|
5206
|
-
*
|
|
5207
|
-
* @example
|
|
5208
|
-
* ```ts
|
|
5209
|
-
* // 내 채널의 최근 공개 영상 10개
|
|
5210
|
-
* const { videos, total } = await cb.video.list({
|
|
5211
|
-
* channel_id: 'ch_abc',
|
|
5212
|
-
* visibility: 'public',
|
|
5213
|
-
* limit: 10,
|
|
5214
|
-
* })
|
|
5215
|
-
* ```
|
|
3891
|
+
* List videos
|
|
5216
3892
|
*/
|
|
5217
3893
|
list(options?: VideoListOptions): Promise<VideoListResponse>;
|
|
5218
3894
|
/**
|
|
@@ -5228,20 +3904,7 @@ declare class VideoAPI {
|
|
|
5228
3904
|
*/
|
|
5229
3905
|
delete(videoId: string): Promise<void>;
|
|
5230
3906
|
/**
|
|
5231
|
-
*
|
|
5232
|
-
*
|
|
5233
|
-
* 반환된 URL 은 `hls.js` 또는 Safari 네이티브 HLS 플레이어에 그대로 전달 가능하다.
|
|
5234
|
-
* 서명된 URL 이므로 만료 시간이 존재하며, 갱신이 필요한 경우 다시 호출한다.
|
|
5235
|
-
*
|
|
5236
|
-
* @param videoId - 대상 영상 ID
|
|
5237
|
-
* @param quality - `auto` (기본) | `1080p` | `720p` | `480p` | `360p` 등 트랜스코딩된 품질 레벨
|
|
5238
|
-
* @returns HLS manifest URL 과 만료 정보
|
|
5239
|
-
*
|
|
5240
|
-
* @example
|
|
5241
|
-
* ```ts
|
|
5242
|
-
* const { url, expires_at } = await cb.video.getStreamUrl(videoId, '720p')
|
|
5243
|
-
* videoElement.src = url
|
|
5244
|
-
* ```
|
|
3907
|
+
* Get streaming URL for a video
|
|
5245
3908
|
*/
|
|
5246
3909
|
getStreamUrl(videoId: string, quality?: string): Promise<StreamURLResponse>;
|
|
5247
3910
|
/**
|
|
@@ -5397,131 +4060,11 @@ declare class VideoAPI {
|
|
|
5397
4060
|
* Submit recommendation feedback
|
|
5398
4061
|
*/
|
|
5399
4062
|
submitFeedback(videoId: string, feedback: 'interested' | 'not_interested'): Promise<void>;
|
|
5400
|
-
/**
|
|
5401
|
-
* Storage sub-namespace for video storage container operations
|
|
5402
|
-
*/
|
|
5403
|
-
readonly storage: {
|
|
5404
|
-
/**
|
|
5405
|
-
* Create a video storage container
|
|
5406
|
-
*/
|
|
5407
|
-
create: (data: CreateVideoStorageRequest) => Promise<VideoStorage>;
|
|
5408
|
-
/**
|
|
5409
|
-
* List video storage containers
|
|
5410
|
-
*/
|
|
5411
|
-
list: () => Promise<VideoStorageListResponse>;
|
|
5412
|
-
/**
|
|
5413
|
-
* Get a video storage container
|
|
5414
|
-
*/
|
|
5415
|
-
get: (storageId: string) => Promise<VideoStorage>;
|
|
5416
|
-
/**
|
|
5417
|
-
* Update a video storage container
|
|
5418
|
-
*/
|
|
5419
|
-
update: (storageId: string, data: UpdateVideoStorageRequest) => Promise<VideoStorage>;
|
|
5420
|
-
/**
|
|
5421
|
-
* Delete a video storage container
|
|
5422
|
-
*/
|
|
5423
|
-
delete: (storageId: string) => Promise<void>;
|
|
5424
|
-
/**
|
|
5425
|
-
* Upload a video to a specific storage via core-server proxy (chunked)
|
|
5426
|
-
*/
|
|
5427
|
-
upload: (storageId: string, file: File, options: StorageUploadOptions) => Promise<Video>;
|
|
5428
|
-
/**
|
|
5429
|
-
* List videos in a specific storage
|
|
5430
|
-
*/
|
|
5431
|
-
listVideos: (storageId: string, options?: VideoListOptions) => Promise<VideoListResponse>;
|
|
5432
|
-
/**
|
|
5433
|
-
* Get a video in a specific storage
|
|
5434
|
-
*/
|
|
5435
|
-
getVideo: (storageId: string, videoId: string) => Promise<Video>;
|
|
5436
|
-
/**
|
|
5437
|
-
* Delete a video from a specific storage
|
|
5438
|
-
*/
|
|
5439
|
-
deleteVideo: (storageId: string, videoId: string) => Promise<void>;
|
|
5440
|
-
/**
|
|
5441
|
-
* Get streaming URL for a video in a specific storage
|
|
5442
|
-
*/
|
|
5443
|
-
getStreamUrl: (storageId: string, videoId: string) => Promise<StreamURLResponse>;
|
|
5444
|
-
/**
|
|
5445
|
-
* Get transcode status for a video in a specific storage
|
|
5446
|
-
*/
|
|
5447
|
-
getTranscodeStatus: (storageId: string, videoId: string) => Promise<TranscodeStatus>;
|
|
5448
|
-
};
|
|
5449
|
-
}
|
|
5450
|
-
|
|
5451
|
-
/**
|
|
5452
|
-
* 게임 서버 기능 opt-in 토글 API.
|
|
5453
|
-
*
|
|
5454
|
-
* v3.1 (2026-04-30+) 부터 도입. 7개 게임 기능 (matchqueue / leaderboard / entity /
|
|
5455
|
-
* scripts / voice / replay / spectator) 은 모두 앱 단위로 명시적 opt-in 해야 사용 가능.
|
|
5456
|
-
*
|
|
5457
|
-
* 정책:
|
|
5458
|
-
* - 신규 앱: 모든 토글 false (App 생성 시 row 자동 삽입)
|
|
5459
|
-
* - 기존 앱: row 가 없으면 레거시 호환으로 모두 ON 으로 응답 (서비스 단절 방지)
|
|
5460
|
-
* - PATCH 후 game-server 캐시는 NATS publish 로 즉시 무효화 (또는 30s TTL)
|
|
5461
|
-
*
|
|
5462
|
-
* @example
|
|
5463
|
-
* ```ts
|
|
5464
|
-
* const cfg = await cb.game.config.get(appId)
|
|
5465
|
-
* if (!cfg.matchqueue_enabled) {
|
|
5466
|
-
* await cb.game.config.set(appId, { matchqueue_enabled: true })
|
|
5467
|
-
* }
|
|
5468
|
-
* ```
|
|
5469
|
-
*
|
|
5470
|
-
* @see docs/game-server/OPT_IN.md
|
|
5471
|
-
*/
|
|
5472
|
-
|
|
5473
|
-
/** 7개 토글 + 메타. */
|
|
5474
|
-
interface GameConfig {
|
|
5475
|
-
matchqueue_enabled: boolean;
|
|
5476
|
-
leaderboard_enabled: boolean;
|
|
5477
|
-
entity_enabled: boolean;
|
|
5478
|
-
scripts_enabled: boolean;
|
|
5479
|
-
voice_enabled: boolean;
|
|
5480
|
-
replay_enabled: boolean;
|
|
5481
|
-
spectator_enabled: boolean;
|
|
5482
|
-
}
|
|
5483
|
-
/** PATCH body — 변경할 필드만 명시 (partial update). */
|
|
5484
|
-
type GameConfigPatch = Partial<GameConfig>;
|
|
5485
|
-
/**
|
|
5486
|
-
* 게임 기능 토글 클라이언트.
|
|
5487
|
-
*
|
|
5488
|
-
* 직접 인스턴스화하지 않고 `cb.game.config` 로 접근.
|
|
5489
|
-
*/
|
|
5490
|
-
declare class GameConfigAPI {
|
|
5491
|
-
private http;
|
|
5492
|
-
private appId?;
|
|
5493
|
-
constructor(http: HttpClient, appId?: string);
|
|
5494
|
-
/**
|
|
5495
|
-
* 현재 토글 상태 조회.
|
|
5496
|
-
*
|
|
5497
|
-
* @param appId 앱 ID (생성자에서 주입한 기본값 사용 가능)
|
|
5498
|
-
*/
|
|
5499
|
-
get(appId?: string): Promise<GameConfig>;
|
|
5500
|
-
/**
|
|
5501
|
-
* 토글 변경. 보낸 필드만 갱신, 나머지는 보존. PATCH 직후 game-server 캐시 즉시 drop
|
|
5502
|
-
* (NATS publish) — TTL 기다릴 필요 없음.
|
|
5503
|
-
*
|
|
5504
|
-
* @example
|
|
5505
|
-
* await cb.game.config.set(appId, { matchqueue_enabled: true, leaderboard_enabled: true })
|
|
5506
|
-
*/
|
|
5507
|
-
set(appId: string | GameConfigPatch, patch?: GameConfigPatch): Promise<GameConfig>;
|
|
5508
|
-
/**
|
|
5509
|
-
* 단일 기능 활성화 — set() 의 편의 wrapper.
|
|
5510
|
-
*
|
|
5511
|
-
* @example await cb.game.config.enable(appId, "matchqueue")
|
|
5512
|
-
*/
|
|
5513
|
-
enable(appId: string, feature: keyof GameConfig): Promise<GameConfig>;
|
|
5514
|
-
/**
|
|
5515
|
-
* 단일 기능 비활성화.
|
|
5516
|
-
*/
|
|
5517
|
-
disable(appId: string, feature: keyof GameConfig): Promise<GameConfig>;
|
|
5518
|
-
private resolveAppId;
|
|
5519
4063
|
}
|
|
5520
4064
|
|
|
5521
4065
|
/**
|
|
5522
4066
|
* Game Server Types
|
|
5523
4067
|
*/
|
|
5524
|
-
|
|
5525
4068
|
/**
|
|
5526
4069
|
* 게임 룸 설정
|
|
5527
4070
|
*/
|
|
@@ -5534,16 +4077,6 @@ interface GameRoomConfig {
|
|
|
5534
4077
|
tickRate?: number;
|
|
5535
4078
|
/** 최대 플레이어 수 (기본 100) */
|
|
5536
4079
|
maxPlayers?: number;
|
|
5537
|
-
/**
|
|
5538
|
-
* 룸에 attach 할 Lua 스크립트 이름. 콘솔 또는 `POST /v1/game/:appID/scripts` 로 업로드+활성화한
|
|
5539
|
-
* 스크립트만 사용 가능. 미지정 시 server tick + delta 만 흐르고 onTick / onJoin / onAction 등
|
|
5540
|
-
* 사용자 hook 은 호출되지 않는다.
|
|
5541
|
-
*
|
|
5542
|
-
* platform-issue 019e123a (2026-05-10) 해결로 추가된 필드. 이전 버전에서 createRoom config 에
|
|
5543
|
-
* `script_name` 을 직접 넣어 호출하던 워크어라운드는 SDK 가 와이어 페이로드에서 자동으로
|
|
5544
|
-
* `script_name` 으로 매핑해 호환된다.
|
|
5545
|
-
*/
|
|
5546
|
-
scriptName?: string;
|
|
5547
4080
|
/** 커스텀 메타데이터 */
|
|
5548
4081
|
metadata?: Record<string, string>;
|
|
5549
4082
|
}
|
|
@@ -5611,7 +4144,7 @@ interface GameRoomInfo {
|
|
|
5611
4144
|
/**
|
|
5612
4145
|
* 게임 서버 메시지 타입
|
|
5613
4146
|
*/
|
|
5614
|
-
type GameServerMessageType = 'room_created' | 'room_joined' | 'room_left' | 'state' | 'delta' | 'player_event' | 'chat' | 'pong' | 'room_list' | 'error'
|
|
4147
|
+
type GameServerMessageType = 'room_created' | 'room_joined' | 'room_left' | 'state' | 'delta' | 'player_event' | 'chat' | 'pong' | 'room_list' | 'error';
|
|
5615
4148
|
/**
|
|
5616
4149
|
* 게임 서버 메시지
|
|
5617
4150
|
* 서버는 모든 필드를 최상위에 보냄 (data 래퍼 없음)
|
|
@@ -5648,30 +4181,6 @@ interface GameServerMessage {
|
|
|
5648
4181
|
timestamp?: number;
|
|
5649
4182
|
client_timestamp?: number;
|
|
5650
4183
|
server_timestamp?: number;
|
|
5651
|
-
phase?: string;
|
|
5652
|
-
feature?: string;
|
|
5653
|
-
script_id?: string;
|
|
5654
|
-
/**
|
|
5655
|
-
* broadcastScriptError 가 onAction 에러 broadcast 시 origin client 식별을 위해
|
|
5656
|
-
* 함께 보내는 필드. sender 본인은 점대점 error 응답으로 받으므로 broadcast 에서
|
|
5657
|
-
* 제외되며, 다른 player 가 누가 액션을 일으켰는지 가시화하는 용도.
|
|
5658
|
-
*/
|
|
5659
|
-
origin_client_id?: string;
|
|
5660
|
-
/**
|
|
5661
|
-
* `code === 'SCRIPT_NOT_FOUND'` 응답에 포함 — createRoom 시 client 가 요청했던
|
|
5662
|
-
* scriptName. 오타/대소문자/스킴 mismatch 디버깅 단서.
|
|
5663
|
-
*/
|
|
5664
|
-
requested?: string;
|
|
5665
|
-
/**
|
|
5666
|
-
* `code === 'SCRIPT_NOT_FOUND'` 응답에 포함 — 현재 app 에 활성(active+version>0)
|
|
5667
|
-
* 상태인 script 이름 목록. 사용자가 후보 중 골라 재시도하기 좋도록 노출.
|
|
5668
|
-
*/
|
|
5669
|
-
available?: string[];
|
|
5670
|
-
reason?: string;
|
|
5671
|
-
script_version?: number;
|
|
5672
|
-
/** room_created 응답 — 서버가 attach 한 lua script 이름 (검증된 값). */
|
|
5673
|
-
script_name?: string;
|
|
5674
|
-
hint?: string;
|
|
5675
4184
|
}
|
|
5676
4185
|
/**
|
|
5677
4186
|
* 플레이어 이벤트
|
|
@@ -5693,74 +4202,11 @@ interface ChatMessage {
|
|
|
5693
4202
|
serverTime: number;
|
|
5694
4203
|
}
|
|
5695
4204
|
/**
|
|
5696
|
-
*
|
|
5697
|
-
*
|
|
5698
|
-
* - `SCRIPT_NOT_FOUND` : createRoom 의 scriptName 이 미존재/비활성. 응답에 requested + available 동봉.
|
|
5699
|
-
* - `NO_ACTION_HANDLER` : action 의 type 에 대응하는 lua handler 미정의 (`onAction` 또는 `handlers[type]`).
|
|
5700
|
-
* - `FEATURE_DISABLED` : entity/matchqueue/leaderboard 등 opt-in feature 가 OFF. feature 필드로 분기.
|
|
5701
|
-
* - `SCRIPT_ERROR` : lua 실행 중 일반 에러 (분류되지 않은 throw / runtime error).
|
|
5702
|
-
* - `SCRIPT_TIMEOUT` : 사용자 hook code 의 context deadline 초과 (기본 100ms). hook 본문이 느림.
|
|
5703
|
-
* - `SCRIPT_SETUP_OVERRUN` : hook 호출 *전* 플랫폼 측 setup phase (스크립트 로드 + state 직렬화 + API 주입) 가
|
|
5704
|
-
* setupBudget(기본 100ms / onInit 1s) 초과. 일반적으로 룸 state 가 너무 큼.
|
|
5705
|
-
* 해결: state 의 큰 데이터를 entity primitive 로 이전, state.dbg.* 누적 중단.
|
|
5706
|
-
* issue 019e2c29 후 도입 (2026-05-16).
|
|
5707
|
-
* - `RATE_LIMITED` : per-app script rate limit 초과 (`SCRIPT_RATE_PER_SEC`).
|
|
5708
|
-
* - `QUOTA_EXCEEDED` : plan 한도(`script_executions/month`) 초과.
|
|
5709
|
-
* - `TIMEOUT` : SDK 측 sendWithHandler timeout (서버 응답 없음).
|
|
5710
|
-
* - `UNKNOWN` : 분류되지 않은 server 에러 (server 에 신규 코드가 생겼는데 SDK 미반영).
|
|
5711
|
-
*
|
|
5712
|
-
* literal autocomplete 를 유지하면서 미래에 server 가 신규 코드를 추가해도 타입 에러가
|
|
5713
|
-
* 안 나도록 `string & {}` 도 union 에 포함 (TypeScript 'string literal type widening' 우회 패턴).
|
|
5714
|
-
*/
|
|
5715
|
-
type GameErrorCode = 'SCRIPT_NOT_FOUND' | 'NO_ACTION_HANDLER' | 'FEATURE_DISABLED' | 'SCRIPT_ERROR' | 'SCRIPT_TIMEOUT' | 'SCRIPT_SETUP_OVERRUN' | 'RATE_LIMITED' | 'QUOTA_EXCEEDED' | 'TIMEOUT' | 'UNKNOWN' | (string & {});
|
|
5716
|
-
/**
|
|
5717
|
-
* 에러 메시지 — server `error` 메시지의 wire format. SDK 사용자에게는 GameError
|
|
5718
|
-
* 인스턴스(class)로 surface 되지만, 본 인터페이스는 raw payload 매핑 + 타입 추론용.
|
|
4205
|
+
* 에러 메시지
|
|
5719
4206
|
*/
|
|
5720
4207
|
interface ErrorMessage {
|
|
5721
|
-
code:
|
|
4208
|
+
code: string;
|
|
5722
4209
|
message: string;
|
|
5723
|
-
/**
|
|
5724
|
-
* 서버측 Lua hook 단계 식별자 — 값이 있으면 lua 실행 에러.
|
|
5725
|
-
* "onJoin" | "onLeave" | "onTick" | "onAction".
|
|
5726
|
-
* 일반 transport / protocol 에러는 phase 없음.
|
|
5727
|
-
*/
|
|
5728
|
-
phase?: 'onJoin' | 'onLeave' | 'onTick' | 'onAction' | (string & {});
|
|
5729
|
-
/**
|
|
5730
|
-
* code === "FEATURE_DISABLED" 일 때 비활성 feature 이름.
|
|
5731
|
-
* "entity" | "matchqueue" | "leaderboard" 등 — `toggle_game_features` 와 1:1 매핑.
|
|
5732
|
-
*/
|
|
5733
|
-
feature?: 'entity' | 'matchqueue' | 'leaderboard' | (string & {});
|
|
5734
|
-
roomId?: string;
|
|
5735
|
-
scriptId?: string;
|
|
5736
|
-
/**
|
|
5737
|
-
* broadcast 형태의 onAction 에러일 때 액션을 일으킨 client. 본인이 아닌 다른
|
|
5738
|
-
* player 에서 발생한 에러를 SDK 사용자가 식별/필터링하기 위한 필드.
|
|
5739
|
-
*/
|
|
5740
|
-
originClientId?: string;
|
|
5741
|
-
/** code === 'SCRIPT_NOT_FOUND' 시 client 가 요청했던 scriptName. */
|
|
5742
|
-
requested?: string;
|
|
5743
|
-
/** code === 'SCRIPT_NOT_FOUND' 시 후보로 노출되는 active script 이름 목록. */
|
|
5744
|
-
available?: string[];
|
|
5745
|
-
}
|
|
5746
|
-
/**
|
|
5747
|
-
* CreateRoomResult — `createRoomDetailed` 의 반환 타입. createRoom 의 호환성 보존을
|
|
5748
|
-
* 위해 별도 메서드로 노출 (createRoom 은 기존대로 `Promise<GameState>` 유지).
|
|
5749
|
-
*
|
|
5750
|
-
* server 의 `room_created` 응답에는 이전엔 room_id + initial_state 만 들어왔으나
|
|
5751
|
-
* platform-issue 019e21dd (NJB regression, 2026-05-13) 의 회귀 가드로 attach 된 lua
|
|
5752
|
-
* script 의 이름/버전이 함께 echo 된다 — client 가 attach 검증 후 mismatch 시
|
|
5753
|
-
* 즉시 throw 할 수 있도록.
|
|
5754
|
-
*/
|
|
5755
|
-
interface CreateRoomResult {
|
|
5756
|
-
/** 서버 생성 룸 UUID (config.roomId 와 항상 같지는 않음 — 서버가 fresh UUID 생성 가능). */
|
|
5757
|
-
roomId: string;
|
|
5758
|
-
/** 초기 상태 스냅샷. 기존 `createRoom` 의 resolve 값과 동일 shape. */
|
|
5759
|
-
state: GameState;
|
|
5760
|
-
/** Attached lua script 이름. config.scriptName 미지정 시 undefined. */
|
|
5761
|
-
scriptName?: string;
|
|
5762
|
-
/** Attached lua script 의 active version (Manager.GetMeta.ActiveVersion). */
|
|
5763
|
-
scriptVersion?: number;
|
|
5764
4210
|
}
|
|
5765
4211
|
/**
|
|
5766
4212
|
* Ping/Pong 응답
|
|
@@ -5769,38 +4215,13 @@ interface PongMessage {
|
|
|
5769
4215
|
clientTimestamp: number;
|
|
5770
4216
|
serverTimestamp: number;
|
|
5771
4217
|
}
|
|
5772
|
-
/**
|
|
5773
|
-
* room_stale 이벤트 페이로드.
|
|
5774
|
-
* 서버 측 hot reload(active_version bump) 등으로 현재 room 의 lua 핸들러가
|
|
5775
|
-
* 갱신됐지만 기존 state 가 보존되어 사용자 lua 의 `state.initialized` 같은
|
|
5776
|
-
* 가드로 `handlers.init` 가 재실행되지 않을 수 있을 때 발화된다.
|
|
5777
|
-
*
|
|
5778
|
-
* 권장 처리: leaveRoom → joinRoom 또는 새 roomId 로 createRoom.
|
|
5779
|
-
* 자동 disconnect 는 SDK 가 하지 않는다 — 정책은 사용자 게임이 결정.
|
|
5780
|
-
*/
|
|
5781
|
-
interface RoomStaleMessage {
|
|
5782
|
-
/** "script_reloaded" | "schema_changed" | "manual" 등 — 자유 문자열 */
|
|
5783
|
-
reason: string;
|
|
5784
|
-
roomId: string;
|
|
5785
|
-
/** appID:scriptName 형태. 없을 수 있음. */
|
|
5786
|
-
scriptId?: string;
|
|
5787
|
-
/** 새 active_version. 없을 수 있음. */
|
|
5788
|
-
scriptVersion?: number;
|
|
5789
|
-
serverTime: number;
|
|
5790
|
-
}
|
|
5791
4218
|
/**
|
|
5792
4219
|
* 게임 클라이언트 이벤트 핸들러
|
|
5793
4220
|
*/
|
|
5794
4221
|
interface GameEventHandlers {
|
|
5795
4222
|
onConnect?: () => void;
|
|
5796
4223
|
onDisconnect?: (event: CloseEvent) => void;
|
|
5797
|
-
|
|
5798
|
-
* - `Event` : WebSocket transport-level 에러 (브라우저 WS API 의 onerror).
|
|
5799
|
-
* - `GameError` : server 가 surface 한 `error` 메시지를 wrap 한 인스턴스 — `.code`,
|
|
5800
|
-
* `.phase`, `.feature`, `.originClientId`, `.requested`, `.available` 모두 노출.
|
|
5801
|
-
* `instanceof GameError` 로 분기하여 UI 표시 차별화 가능.
|
|
5802
|
-
*/
|
|
5803
|
-
onError?: (error: Event | GameError) => void;
|
|
4224
|
+
onError?: (error: Event | ErrorMessage) => void;
|
|
5804
4225
|
onStateUpdate?: (state: GameState) => void;
|
|
5805
4226
|
onDelta?: (delta: GameDelta) => void;
|
|
5806
4227
|
onAction?: (action: {
|
|
@@ -5813,22 +4234,6 @@ interface GameEventHandlers {
|
|
|
5813
4234
|
onPlayerLeft?: (player: GamePlayer) => void;
|
|
5814
4235
|
onChat?: (message: ChatMessage) => void;
|
|
5815
4236
|
onPong?: (pong: PongMessage) => void;
|
|
5816
|
-
/**
|
|
5817
|
-
* 커스텀 broadcast 메시지 핸들러 — 서버 Lua 의 `room.broadcast(data)` / `room.send_to(clientId, data)`
|
|
5818
|
-
* 로 보낸, SDK 가 모르는 `type` 의 메시지가 여기로 흘러온다. `delta`/`state`/`chat`/`player_event`/`error`
|
|
5819
|
-
* 같은 표준 타입은 전용 핸들러로 가고 여기엔 오지 않는다.
|
|
5820
|
-
*
|
|
5821
|
-
* 게임별 커스텀 프로토콜(예: `{ type: "chunk", ... }`, `{ type: "turn_played", ... }`)은
|
|
5822
|
-
* 이 핸들러에서 `msg.type` 으로 분기한다.
|
|
5823
|
-
*/
|
|
5824
|
-
onMessage?: (msg: Record<string, unknown> & {
|
|
5825
|
-
type: string;
|
|
5826
|
-
}) => void;
|
|
5827
|
-
/**
|
|
5828
|
-
* 서버가 room 을 stale 로 표시했을 때 발화. 자세한 사양은 `RoomStaleMessage` 참고.
|
|
5829
|
-
* 미설정 시 SDK 는 console.warn 으로 가시화만 하고 자동 동작은 하지 않는다.
|
|
5830
|
-
*/
|
|
5831
|
-
onRoomStale?: (msg: RoomStaleMessage) => void;
|
|
5832
4237
|
}
|
|
5833
4238
|
/**
|
|
5834
4239
|
* 게임 클라이언트 설정
|
|
@@ -5838,8 +4243,8 @@ interface GameClientConfig {
|
|
|
5838
4243
|
gameServerUrl?: string;
|
|
5839
4244
|
/** 앱 ID */
|
|
5840
4245
|
appId?: string;
|
|
5841
|
-
/**
|
|
5842
|
-
|
|
4246
|
+
/** API Key */
|
|
4247
|
+
apiKey?: string;
|
|
5843
4248
|
/** 액세스 토큰 */
|
|
5844
4249
|
accessToken?: string;
|
|
5845
4250
|
/** 클라이언트 ID */
|
|
@@ -5969,202 +4374,7 @@ interface LobbyInvite {
|
|
|
5969
4374
|
createdAt: string;
|
|
5970
4375
|
expiresAt: string;
|
|
5971
4376
|
}
|
|
5972
|
-
interface PartyInfo {
|
|
5973
|
-
id: string;
|
|
5974
|
-
app_id: string;
|
|
5975
|
-
leader_id: string;
|
|
5976
|
-
members: PartyMember[];
|
|
5977
|
-
max_size: number;
|
|
5978
|
-
settings?: Record<string, string>;
|
|
5979
|
-
state: string;
|
|
5980
|
-
created_at: string;
|
|
5981
|
-
updated_at: string;
|
|
5982
|
-
}
|
|
5983
|
-
interface PartyMember {
|
|
5984
|
-
player_id: string;
|
|
5985
|
-
display_name?: string;
|
|
5986
|
-
ready: boolean;
|
|
5987
|
-
role: string;
|
|
5988
|
-
joined_at: string;
|
|
5989
|
-
metadata?: Record<string, string>;
|
|
5990
|
-
}
|
|
5991
|
-
interface PartyInvite {
|
|
5992
|
-
invite_id: string;
|
|
5993
|
-
party_id: string;
|
|
5994
|
-
inviter_id: string;
|
|
5995
|
-
status: string;
|
|
5996
|
-
expires_at: string;
|
|
5997
|
-
}
|
|
5998
|
-
interface SpectatorInfo {
|
|
5999
|
-
id: string;
|
|
6000
|
-
user_id?: string;
|
|
6001
|
-
room_id: string;
|
|
6002
|
-
mode: "free" | "follow" | "director";
|
|
6003
|
-
target_id?: string;
|
|
6004
|
-
joined_at: string;
|
|
6005
|
-
delay_seconds?: number;
|
|
6006
|
-
}
|
|
6007
|
-
interface SpectatorState {
|
|
6008
|
-
room_id: string;
|
|
6009
|
-
tick: number;
|
|
6010
|
-
timestamp: number;
|
|
6011
|
-
players: SpectatorPlayerState[];
|
|
6012
|
-
game_state?: Record<string, unknown>;
|
|
6013
|
-
events?: Record<string, unknown>[];
|
|
6014
|
-
}
|
|
6015
|
-
interface SpectatorPlayerState {
|
|
6016
|
-
id: string;
|
|
6017
|
-
display_name: string;
|
|
6018
|
-
position: {
|
|
6019
|
-
x: number;
|
|
6020
|
-
y: number;
|
|
6021
|
-
z: number;
|
|
6022
|
-
};
|
|
6023
|
-
health?: number;
|
|
6024
|
-
score?: number;
|
|
6025
|
-
is_alive: boolean;
|
|
6026
|
-
}
|
|
6027
|
-
interface LeaderboardEntry {
|
|
6028
|
-
rank: number;
|
|
6029
|
-
player_id: string;
|
|
6030
|
-
display_name: string;
|
|
6031
|
-
rating: number;
|
|
6032
|
-
wins: number;
|
|
6033
|
-
losses: number;
|
|
6034
|
-
games_played: number;
|
|
6035
|
-
win_rate: number;
|
|
6036
|
-
tier: string;
|
|
6037
|
-
division: number;
|
|
6038
|
-
updated_at: string;
|
|
6039
|
-
}
|
|
6040
|
-
interface PlayerStats {
|
|
6041
|
-
player_id: string;
|
|
6042
|
-
rating: number;
|
|
6043
|
-
wins: number;
|
|
6044
|
-
losses: number;
|
|
6045
|
-
games_played: number;
|
|
6046
|
-
win_rate: number;
|
|
6047
|
-
tier: string;
|
|
6048
|
-
division: number;
|
|
6049
|
-
match_history: MatchResult[];
|
|
6050
|
-
}
|
|
6051
|
-
interface MatchResult {
|
|
6052
|
-
match_id: string;
|
|
6053
|
-
result: "win" | "loss" | "draw";
|
|
6054
|
-
rating_change: number;
|
|
6055
|
-
played_at: string;
|
|
6056
|
-
}
|
|
6057
|
-
interface VoiceChannel {
|
|
6058
|
-
id: string;
|
|
6059
|
-
room_id: string;
|
|
6060
|
-
name: string;
|
|
6061
|
-
type: "global" | "team" | "proximity" | "private" | "spectator";
|
|
6062
|
-
team_id?: string;
|
|
6063
|
-
max_members: number;
|
|
6064
|
-
members: Record<string, VoiceMember>;
|
|
6065
|
-
webrtc_room_id: string;
|
|
6066
|
-
created_at: string;
|
|
6067
|
-
}
|
|
6068
|
-
interface VoiceMember {
|
|
6069
|
-
player_id: string;
|
|
6070
|
-
display_name: string;
|
|
6071
|
-
joined_at: string;
|
|
6072
|
-
webrtc_url?: string;
|
|
6073
|
-
}
|
|
6074
|
-
interface ReplayInfo {
|
|
6075
|
-
id: string;
|
|
6076
|
-
room_id: string;
|
|
6077
|
-
game_type: string;
|
|
6078
|
-
map_name?: string;
|
|
6079
|
-
duration: number;
|
|
6080
|
-
tick_rate: number;
|
|
6081
|
-
start_tick: number;
|
|
6082
|
-
end_tick: number;
|
|
6083
|
-
players: ReplayPlayerInfo[];
|
|
6084
|
-
file_size: number;
|
|
6085
|
-
created_at: string;
|
|
6086
|
-
schema_version?: string;
|
|
6087
|
-
}
|
|
6088
|
-
interface ReplayPlayerInfo {
|
|
6089
|
-
player_id: string;
|
|
6090
|
-
display_name: string;
|
|
6091
|
-
team_id?: string;
|
|
6092
|
-
}
|
|
6093
|
-
interface ReplayHighlight {
|
|
6094
|
-
tick: number;
|
|
6095
|
-
type: string;
|
|
6096
|
-
actor_id: string;
|
|
6097
|
-
score: number;
|
|
6098
|
-
}
|
|
6099
|
-
/** Matchqueue ticket — attributes 는 free-form (rating/region 등 자유). */
|
|
6100
|
-
interface MatchqueueTicket {
|
|
6101
|
-
ticket_id: string;
|
|
6102
|
-
queue_key: string;
|
|
6103
|
-
attributes?: Record<string, unknown>;
|
|
6104
|
-
enqueued_at: string;
|
|
6105
|
-
ttl_at?: string;
|
|
6106
|
-
}
|
|
6107
|
-
interface MatchqueueListResponse {
|
|
6108
|
-
tickets: MatchqueueTicket[];
|
|
6109
|
-
count: number;
|
|
6110
|
-
}
|
|
6111
|
-
/**
|
|
6112
|
-
* v3.0 Leaderboard score entry — score 는 사용자 Lua 의 ELO/MMR 공식 결과.
|
|
6113
|
-
* rank 는 GetTop/GetRank 시점에만 채워진다 (저장은 안 됨).
|
|
6114
|
-
*
|
|
6115
|
-
* v2.x 의 LeaderboardEntry (player_id/rating/tier/wins/losses 등) 와 다른 시그니처라
|
|
6116
|
-
* 새 이름 사용. v2 LeaderboardEntry 는 v3.0 에서 deprecated.
|
|
6117
|
-
*/
|
|
6118
|
-
interface LeaderboardScoreEntry {
|
|
6119
|
-
member: string;
|
|
6120
|
-
score: number;
|
|
6121
|
-
updated_at: string;
|
|
6122
|
-
rank?: number;
|
|
6123
|
-
}
|
|
6124
|
-
interface LeaderboardListResponse {
|
|
6125
|
-
entries: LeaderboardScoreEntry[];
|
|
6126
|
-
count: number;
|
|
6127
|
-
}
|
|
6128
|
-
/** Lua script — 메타 + 단일 버전. */
|
|
6129
|
-
interface ScriptMeta {
|
|
6130
|
-
app_id: string;
|
|
6131
|
-
name: string;
|
|
6132
|
-
active_version: number;
|
|
6133
|
-
latest_version: number;
|
|
6134
|
-
status: "active" | "staging" | "disabled";
|
|
6135
|
-
updated_at: string;
|
|
6136
|
-
}
|
|
6137
|
-
interface ScriptVersion {
|
|
6138
|
-
app_id: string;
|
|
6139
|
-
name: string;
|
|
6140
|
-
version: number;
|
|
6141
|
-
hash: string;
|
|
6142
|
-
code: string;
|
|
6143
|
-
uploaded_at: string;
|
|
6144
|
-
uploaded_by?: string;
|
|
6145
|
-
}
|
|
6146
|
-
interface ScriptListResponse {
|
|
6147
|
-
scripts: ScriptMeta[];
|
|
6148
|
-
count: number;
|
|
6149
|
-
}
|
|
6150
|
-
interface ScriptVersionListResponse {
|
|
6151
|
-
versions: ScriptVersion[];
|
|
6152
|
-
count: number;
|
|
6153
|
-
}
|
|
6154
|
-
interface ScriptDetailResponse {
|
|
6155
|
-
meta: ScriptMeta;
|
|
6156
|
-
active?: ScriptVersion;
|
|
6157
|
-
}
|
|
6158
4377
|
|
|
6159
|
-
/**
|
|
6160
|
-
* 게임 서버 `create_room` 메시지 페이로드는 snake_case 필드를 기대한다 (Go 핸들러 JSON 태그).
|
|
6161
|
-
* SDK 의 GameRoomConfig 는 camelCase 이므로, scriptName / tickRate / maxPlayers / roomId /
|
|
6162
|
-
* categoryId 를 와이어 형식으로 매핑한다. 추가 필드(metadata)는 그대로 통과.
|
|
6163
|
-
*
|
|
6164
|
-
* platform-issue 019e123a (2026-05-10) 의 회귀 가드 — scriptName 누락 시 RoomConfig.ScriptID
|
|
6165
|
-
* 가 비어 onTick / onPlayerJoin 등이 silent skip 되던 문제 차단.
|
|
6166
|
-
*/
|
|
6167
|
-
declare function toCreateRoomWire(config: GameRoomConfig): Record<string, unknown>;
|
|
6168
4378
|
/**
|
|
6169
4379
|
* 게임 룸 클라이언트
|
|
6170
4380
|
* WebSocket 연결을 관리하고 게임 상태를 동기화합니다.
|
|
@@ -6179,8 +4389,6 @@ declare class GameRoom {
|
|
|
6179
4389
|
private actionSequence;
|
|
6180
4390
|
private _roomId;
|
|
6181
4391
|
private _state;
|
|
6182
|
-
private _scriptName;
|
|
6183
|
-
private _scriptVersion;
|
|
6184
4392
|
private _isConnected;
|
|
6185
4393
|
constructor(config: GameClientConfig);
|
|
6186
4394
|
/**
|
|
@@ -6208,29 +4416,9 @@ declare class GameRoom {
|
|
|
6208
4416
|
*/
|
|
6209
4417
|
disconnect(): void;
|
|
6210
4418
|
/**
|
|
6211
|
-
* 룸 생성
|
|
6212
|
-
*
|
|
6213
|
-
* Attached script 의 검증(scriptName/scriptVersion echo 검사) 이 필요하면
|
|
6214
|
-
* 인스턴스 getter (`room.scriptName`, `room.scriptVersion`) 를 함께 사용하거나,
|
|
6215
|
-
* 메타까지 한 번에 받고 싶다면 {@link createRoomDetailed} 를 사용한다.
|
|
6216
|
-
*
|
|
6217
|
-
* 미존재/비활성 scriptName 은 서버가 `SCRIPT_NOT_FOUND` 로 즉시 reject 한다.
|
|
6218
|
-
* reject 값은 `GameError` 인스턴스이며 `.code`/`.requested`/`.available` 로 분기 가능.
|
|
4419
|
+
* 룸 생성
|
|
6219
4420
|
*/
|
|
6220
4421
|
createRoom(config?: GameRoomConfig): Promise<GameState>;
|
|
6221
|
-
/**
|
|
6222
|
-
* 룸 생성 + 메타 — server 가 attach 한 lua script 이름/버전을 함께 반환.
|
|
6223
|
-
*
|
|
6224
|
-
* @example
|
|
6225
|
-
* const { state, scriptName, scriptVersion } = await room.createRoomDetailed({ scriptName: 'njb-main' })
|
|
6226
|
-
* if (scriptName !== 'njb-main') throw new Error('script mismatch')
|
|
6227
|
-
* console.log('attached', scriptName, 'v', scriptVersion)
|
|
6228
|
-
*/
|
|
6229
|
-
createRoomDetailed(config?: GameRoomConfig): Promise<CreateRoomResult>;
|
|
6230
|
-
/** Attached lua script 이름 — createRoom 이후 server 가 echo 한 값. */
|
|
6231
|
-
get scriptName(): string | null;
|
|
6232
|
-
/** Attached lua script 의 active version. */
|
|
6233
|
-
get scriptVersion(): number | null;
|
|
6234
4422
|
/**
|
|
6235
4423
|
* 룸 참가
|
|
6236
4424
|
*/
|
|
@@ -6279,18 +4467,9 @@ declare class GameAPI {
|
|
|
6279
4467
|
private http;
|
|
6280
4468
|
private gameServerUrl;
|
|
6281
4469
|
private appId?;
|
|
6282
|
-
/**
|
|
6283
|
-
* 게임 기능 opt-in 토글 (v3.1+). `cb.game.config.get/set` 으로 호출.
|
|
6284
|
-
* 자세한 내용은 [GameConfigAPI] 참고.
|
|
6285
|
-
*/
|
|
6286
|
-
readonly config: GameConfigAPI;
|
|
6287
4470
|
constructor(http: HttpClient, gameServerUrl?: string, appId?: string);
|
|
6288
4471
|
/**
|
|
6289
|
-
* 게임 룸 클라이언트
|
|
6290
|
-
*
|
|
6291
|
-
* `appId` 는 `createClient({ appId })` 로 호출별 지정하거나, 생략 시 `new ConnectBase({ appId })`
|
|
6292
|
-
* 의 전역 값을 사용한다. 둘 다 없으면 `connect()` 가 명확한 에러로 reject 한다 — 빈 appId 로
|
|
6293
|
-
* `/v1/game//ws` 에 붙어 server 측이 SCRIPT_NOT_FOUND 로 깨지던 silent 회귀 차단 (NJB 019e2210).
|
|
4472
|
+
* 게임 룸 클라이언트 생성
|
|
6294
4473
|
*/
|
|
6295
4474
|
createClient(config: Omit<GameClientConfig, 'gameServerUrl'>): GameRoom;
|
|
6296
4475
|
/**
|
|
@@ -6303,138 +4482,98 @@ declare class GameAPI {
|
|
|
6303
4482
|
getRoom(roomId: string): Promise<GameRoomInfo>;
|
|
6304
4483
|
/**
|
|
6305
4484
|
* 룸 생성 (HTTP, gRPC 대안)
|
|
6306
|
-
*
|
|
6307
|
-
* @deprecated 현재 SDK public 경로로 노출되지 않습니다. 콘솔(admin) 에서 진행하거나 백엔드 public 경로 오픈을 요청하세요.
|
|
6308
4485
|
*/
|
|
6309
|
-
createRoom(
|
|
4486
|
+
createRoom(appId: string, config?: GameRoomConfig): Promise<GameRoomInfo>;
|
|
6310
4487
|
/**
|
|
6311
4488
|
* 룸 삭제 (HTTP)
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
*/
|
|
6315
|
-
deleteRoom(_roomId: string): Promise<void>;
|
|
6316
|
-
joinSpectator(roomId: string, playerId: string): Promise<SpectatorInfo>;
|
|
6317
|
-
leaveSpectator(roomId: string, spectatorId: string): Promise<void>;
|
|
6318
|
-
getSpectators(roomId: string): Promise<SpectatorInfo[]>;
|
|
6319
|
-
joinVoiceChannel(roomId: string, playerId: string): Promise<VoiceChannel>;
|
|
6320
|
-
leaveVoiceChannel(roomId: string, playerId: string): Promise<void>;
|
|
6321
|
-
setMute(playerId: string, muted: boolean): Promise<void>;
|
|
6322
|
-
listReplays(roomId?: string): Promise<ReplayInfo[]>;
|
|
6323
|
-
getReplay(replayId: string): Promise<ReplayInfo>;
|
|
6324
|
-
downloadReplay(replayId: string): Promise<ArrayBuffer>;
|
|
6325
|
-
getReplayHighlights(replayId: string): Promise<ReplayHighlight[]>;
|
|
6326
|
-
private getHeaders;
|
|
6327
|
-
private gameFetch;
|
|
4489
|
+
*/
|
|
4490
|
+
deleteRoom(roomId: string): Promise<void>;
|
|
6328
4491
|
/**
|
|
6329
|
-
*
|
|
6330
|
-
*
|
|
6331
|
-
* @example
|
|
6332
|
-
* await cb.game.enqueueMatch(appId, "ranked", userId, {
|
|
6333
|
-
* rating: 1500, region: "asia", team_size: 5,
|
|
6334
|
-
* }, 60)
|
|
6335
|
-
*
|
|
6336
|
-
* @constraints appId/queueKey/ticketId 는 [a-zA-Z0-9_-] 만 허용. ttlSec=0 이면 만료 없음.
|
|
4492
|
+
* 매치메이킹 큐에 참가
|
|
6337
4493
|
*/
|
|
6338
|
-
|
|
4494
|
+
joinQueue(req: JoinQueueRequest): Promise<MatchmakingTicket>;
|
|
6339
4495
|
/**
|
|
6340
|
-
*
|
|
6341
|
-
*
|
|
6342
|
-
* @example const tickets = await cb.game.listMatchqueue(appId, "ranked")
|
|
4496
|
+
* 매치메이킹 큐에서 탈퇴
|
|
6343
4497
|
*/
|
|
6344
|
-
|
|
4498
|
+
leaveQueue(ticketId: string): Promise<void>;
|
|
6345
4499
|
/**
|
|
6346
|
-
*
|
|
4500
|
+
* 매치메이킹 상태 조회
|
|
6347
4501
|
*/
|
|
6348
|
-
|
|
4502
|
+
getMatchStatus(params: {
|
|
4503
|
+
ticketId?: string;
|
|
4504
|
+
playerId?: string;
|
|
4505
|
+
}): Promise<MatchmakingTicket>;
|
|
6349
4506
|
/**
|
|
6350
|
-
*
|
|
6351
|
-
*
|
|
6352
|
-
* @example
|
|
6353
|
-
* await cb.game.submitScore(appId, "global_elo", userId, 32, "incr")
|
|
4507
|
+
* 로비 목록 조회
|
|
6354
4508
|
*/
|
|
6355
|
-
|
|
4509
|
+
listLobbies(): Promise<LobbyInfo[]>;
|
|
6356
4510
|
/**
|
|
6357
|
-
*
|
|
4511
|
+
* 로비 생성
|
|
6358
4512
|
*/
|
|
6359
|
-
|
|
4513
|
+
createLobby(req: CreateLobbyRequest): Promise<LobbyInfo>;
|
|
6360
4514
|
/**
|
|
6361
|
-
*
|
|
4515
|
+
* 로비 상세 조회
|
|
6362
4516
|
*/
|
|
6363
|
-
|
|
4517
|
+
getLobby(lobbyId: string): Promise<LobbyInfo>;
|
|
6364
4518
|
/**
|
|
6365
|
-
*
|
|
4519
|
+
* 로비 참가
|
|
6366
4520
|
*/
|
|
6367
|
-
|
|
4521
|
+
joinLobby(lobbyId: string, playerId: string, displayName?: string, password?: string): Promise<{
|
|
4522
|
+
lobbyId: string;
|
|
4523
|
+
}>;
|
|
6368
4524
|
/**
|
|
6369
|
-
*
|
|
4525
|
+
* 로비 퇴장
|
|
6370
4526
|
*/
|
|
6371
|
-
|
|
4527
|
+
leaveLobby(lobbyId: string, playerId: string): Promise<void>;
|
|
6372
4528
|
/**
|
|
6373
|
-
*
|
|
4529
|
+
* 레디 상태 토글
|
|
6374
4530
|
*/
|
|
6375
|
-
|
|
4531
|
+
toggleReady(lobbyId: string, playerId: string, ready: boolean): Promise<void>;
|
|
6376
4532
|
/**
|
|
6377
|
-
*
|
|
6378
|
-
*
|
|
6379
|
-
* @example
|
|
6380
|
-
* await cb.game.uploadScript(appId, "ranked_br", fs.readFileSync("./ranked.lua", "utf-8"))
|
|
4533
|
+
* 게임 시작 (호스트만)
|
|
6381
4534
|
*/
|
|
6382
|
-
|
|
4535
|
+
startGame(lobbyId: string, hostId: string): Promise<{
|
|
4536
|
+
roomId: string;
|
|
4537
|
+
}>;
|
|
6383
4538
|
/**
|
|
6384
|
-
*
|
|
4539
|
+
* 플레이어 추방 (호스트만)
|
|
6385
4540
|
*/
|
|
6386
|
-
|
|
4541
|
+
kickPlayer(lobbyId: string, hostId: string, targetPlayerId: string): Promise<void>;
|
|
6387
4542
|
/**
|
|
6388
|
-
*
|
|
4543
|
+
* 로비 설정 업데이트 (호스트만)
|
|
6389
4544
|
*/
|
|
6390
|
-
|
|
4545
|
+
updateLobby(lobbyId: string, req: UpdateLobbyRequest): Promise<LobbyInfo>;
|
|
6391
4546
|
/**
|
|
6392
|
-
*
|
|
4547
|
+
* 로비 채팅 전송
|
|
6393
4548
|
*/
|
|
6394
|
-
|
|
4549
|
+
sendLobbyChat(lobbyId: string, playerId: string, message: string): Promise<void>;
|
|
6395
4550
|
/**
|
|
6396
|
-
*
|
|
4551
|
+
* 플레이어 초대
|
|
6397
4552
|
*/
|
|
6398
|
-
|
|
4553
|
+
invitePlayer(lobbyId: string, inviterId: string, inviteeId: string): Promise<LobbyInvite>;
|
|
6399
4554
|
/**
|
|
6400
|
-
*
|
|
4555
|
+
* 초대 수락
|
|
6401
4556
|
*/
|
|
6402
|
-
|
|
4557
|
+
acceptInvite(inviteId: string, playerId: string, displayName?: string): Promise<{
|
|
4558
|
+
lobbyId: string;
|
|
4559
|
+
}>;
|
|
6403
4560
|
/**
|
|
6404
|
-
*
|
|
6405
|
-
* 이후 {@link activateScript} 로 재활성화할 수 있다.
|
|
6406
|
-
*
|
|
6407
|
-
* v3.14.0 BREAKING — 이전엔 `disableScript` 가 `DELETE /scripts/:name` 을 호출해
|
|
6408
|
-
* Disable 매핑이었으나, server 측 `DELETE` 가 hard-delete 로 분리됨에 따라
|
|
6409
|
-
* `POST /scripts/:name/deactivate` 로 endpoint 이동. 메서드명도 의도 명확화 위해 rename.
|
|
4561
|
+
* 초대 거절
|
|
6410
4562
|
*/
|
|
6411
|
-
|
|
4563
|
+
declineInvite(inviteId: string, playerId: string): Promise<void>;
|
|
6412
4564
|
/**
|
|
6413
|
-
*
|
|
6414
|
-
*
|
|
6415
|
-
* 잘못 업로드된 스크립트나 더 이상 사용하지 않는 슬롯을 정리할 때 사용. 단순 비활성화는
|
|
6416
|
-
* {@link deactivateScript} 를 사용한다 (코드 보존, 재활성화 가능).
|
|
6417
|
-
*
|
|
6418
|
-
* v3.14.0 신규 — server 측 `DELETE /scripts/:name` 의 의미가 Disable → hard-delete 로
|
|
6419
|
-
* 변경된 것에 대응.
|
|
4565
|
+
* 플레이어의 받은 초대 목록
|
|
6420
4566
|
*/
|
|
6421
|
-
|
|
4567
|
+
getPlayerInvites(playerId: string): Promise<LobbyInvite[]>;
|
|
4568
|
+
private getHeaders;
|
|
6422
4569
|
}
|
|
6423
4570
|
|
|
6424
|
-
interface
|
|
6425
|
-
is_connected: boolean;
|
|
6426
|
-
email?: string;
|
|
6427
|
-
account_id?: string;
|
|
6428
|
-
}
|
|
6429
|
-
interface AdmobConnectionInfo {
|
|
4571
|
+
interface GoogleConnectionStatus {
|
|
6430
4572
|
is_connected: boolean;
|
|
6431
4573
|
email?: string;
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
interface GoogleConnectionStatus {
|
|
6436
|
-
adsense: AdsenseConnectionInfo;
|
|
6437
|
-
admob: AdmobConnectionInfo;
|
|
4574
|
+
adsense_account_id?: string;
|
|
4575
|
+
admob_account_id?: string;
|
|
4576
|
+
admob_publisher_id?: string;
|
|
6438
4577
|
}
|
|
6439
4578
|
interface AdReportSummary {
|
|
6440
4579
|
total_earnings: number;
|
|
@@ -6486,18 +4625,15 @@ declare class AdsAPI {
|
|
|
6486
4625
|
*/
|
|
6487
4626
|
private getPublicPrefix;
|
|
6488
4627
|
/**
|
|
6489
|
-
* AdSense
|
|
4628
|
+
* AdSense 연결 상태 확인
|
|
6490
4629
|
*
|
|
6491
|
-
* @returns
|
|
4630
|
+
* @returns 연결 상태, 이메일, AdSense 계정 ID
|
|
6492
4631
|
*
|
|
6493
4632
|
* @example
|
|
6494
4633
|
* ```typescript
|
|
6495
4634
|
* const status = await cb.ads.getConnectionStatus()
|
|
6496
|
-
* if (status.
|
|
6497
|
-
* console.log('
|
|
6498
|
-
* }
|
|
6499
|
-
* if (status.admob.is_connected) {
|
|
6500
|
-
* console.log('AdMob 연결됨:', status.admob.account_id, status.admob.publisher_id)
|
|
4635
|
+
* if (status.is_connected) {
|
|
4636
|
+
* console.log('연결됨:', status.email)
|
|
6501
4637
|
* }
|
|
6502
4638
|
* ```
|
|
6503
4639
|
*/
|
|
@@ -6572,7 +4708,7 @@ declare class AdsAPI {
|
|
|
6572
4708
|
* ```typescript
|
|
6573
4709
|
* import ConnectBase from 'connectbase-client'
|
|
6574
4710
|
*
|
|
6575
|
-
* const cb = new ConnectBase({
|
|
4711
|
+
* const cb = new ConnectBase({ apiKey: 'your-api-key' })
|
|
6576
4712
|
*
|
|
6577
4713
|
* // 플랫폼 감지
|
|
6578
4714
|
* const platform = cb.native.getPlatform() // 'web' | 'mobile' | 'desktop'
|
|
@@ -7030,47 +5166,7 @@ interface CreateDocumentRequest {
|
|
|
7030
5166
|
source_type?: 'file' | 'text' | 'url';
|
|
7031
5167
|
content?: string;
|
|
7032
5168
|
source_url?: string;
|
|
7033
|
-
/**
|
|
7034
|
-
* source_type='file' 일 때 사용. 바이너리를 base64 로 인코딩해서 보낸다.
|
|
7035
|
-
* 서버가 PDF / DOCX / text 류를 자동으로 텍스트 추출 → 청킹·인덱싱 한다.
|
|
7036
|
-
* 파일 50MB 상한, 이미지 OCR / 스캔 PDF 는 미지원.
|
|
7037
|
-
* 일반적으로는 [`KnowledgeAPI.addDocumentFromFile`](../api/knowledge.ts) 헬퍼를 사용하면
|
|
7038
|
-
* Blob / File 로 직접 넘길 수 있다.
|
|
7039
|
-
*/
|
|
7040
|
-
file_content?: string;
|
|
7041
|
-
/**
|
|
7042
|
-
* file_content 의 MIME (예: 'application/pdf',
|
|
7043
|
-
* 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/markdown').
|
|
7044
|
-
* 비어있으면 서버가 매직 바이트로 자동 추정 — 정확도를 위해 명시 권장.
|
|
7045
|
-
*/
|
|
7046
|
-
mime_type?: string;
|
|
7047
|
-
/**
|
|
7048
|
-
* 클라이언트가 지정하는 멱등(upsert) 키. 같은 지식 베이스 안에서 유일하다.
|
|
7049
|
-
* 같은 `external_id` 로 다시 `addDocument` 하면 새 문서를 만들지 않고 기존 문서를
|
|
7050
|
-
* 교체(update)한다 — `listDocuments` 로 기존 문서를 찾아 지울 필요 없이
|
|
7051
|
-
* idempotent 한 동기화가 가능하다. 문서 id 도 그대로 유지된다.
|
|
7052
|
-
*/
|
|
7053
|
-
external_id?: string;
|
|
7054
|
-
metadata?: Record<string, unknown>;
|
|
7055
|
-
}
|
|
7056
|
-
/**
|
|
7057
|
-
* 문서 update/upsert 요청. 보낸 필드만 교체된다 (생략한 필드는 변경 없음).
|
|
7058
|
-
*
|
|
7059
|
-
* `content` / `file_content` / `metadata` 중 하나라도 보내면 서버가 전체 재색인을 수행한다
|
|
7060
|
-
* (기존 청크 삭제 → 재청킹 → 재색인). RAG 특성상 콘텐츠가 바뀌면 청크 경계가 바뀌어
|
|
7061
|
-
* 부분 수정이 불가능하며, 재색인 시 색인 토큰이 다시 과금된다.
|
|
7062
|
-
* `name` / `external_id` 만 보내면 재색인 없이 라벨·멱등 키만 변경된다.
|
|
7063
|
-
* 문서 id 는 항상 유지되므로 검색 결과의 `document_id` 참조가 깨지지 않는다.
|
|
7064
|
-
*/
|
|
7065
|
-
interface UpdateDocumentRequest {
|
|
7066
|
-
name?: string;
|
|
7067
|
-
content?: string;
|
|
7068
|
-
/** base64 인코딩 파일 (파일 재업로드, PDF/DOCX/text). content 보다 우선하며 source_type 무관하게 추출. */
|
|
7069
|
-
file_content?: string;
|
|
7070
|
-
/** file_content 의 MIME. 비어있으면 서버 자동 추정. */
|
|
7071
|
-
mime_type?: string;
|
|
7072
5169
|
metadata?: Record<string, unknown>;
|
|
7073
|
-
external_id?: string;
|
|
7074
5170
|
}
|
|
7075
5171
|
interface DocumentResponse {
|
|
7076
5172
|
id: string;
|
|
@@ -7078,7 +5174,6 @@ interface DocumentResponse {
|
|
|
7078
5174
|
source_type: string;
|
|
7079
5175
|
mime_type?: string;
|
|
7080
5176
|
source_url?: string;
|
|
7081
|
-
external_id?: string;
|
|
7082
5177
|
file_size: number;
|
|
7083
5178
|
chunk_count: number;
|
|
7084
5179
|
status: 'pending' | 'processing' | 'ready' | 'failed';
|
|
@@ -7093,35 +5188,9 @@ interface ListDocumentsResponse {
|
|
|
7093
5188
|
documents: DocumentResponse[];
|
|
7094
5189
|
total_count: number;
|
|
7095
5190
|
}
|
|
7096
|
-
/**
|
|
7097
|
-
* 사용자 격리용 magic 토큰. `where` 값에 이 문자열을 넣으면 서버가
|
|
7098
|
-
* 인증된 AppMember ID 로 자동 치환한다 (클라이언트 변조 불가).
|
|
7099
|
-
*
|
|
7100
|
-
* AppMember JWT 가 함께 오지 않은 호출에서 사용하면 401.
|
|
7101
|
-
*/
|
|
7102
|
-
declare const AUTH_MEMBER_ID_TOKEN: "$auth.member_id";
|
|
7103
|
-
/**
|
|
7104
|
-
* 검색 요청
|
|
7105
|
-
* @example { query: "환불 방법", top_k: 5, agentic: true }
|
|
7106
|
-
*
|
|
7107
|
-
* 사용자별 격리 (AppMember JWT 가 Authorization 헤더로 함께 올 때):
|
|
7108
|
-
* - 서버가 자동으로 본인 metadata.user_id 문서로 결과를 제한.
|
|
7109
|
-
* - `where` 로 추가 필터를 걸 수 있음. magic 토큰 사용 예:
|
|
7110
|
-
* `where: { 'metadata.tag': 'work' }`
|
|
7111
|
-
*/
|
|
7112
5191
|
interface KnowledgeSearchRequest {
|
|
7113
|
-
/** 검색 쿼리 (필수) */
|
|
7114
5192
|
query: string;
|
|
7115
|
-
/** 반환할 결과 수 (기본: KB 설정값) */
|
|
7116
5193
|
top_k?: number;
|
|
7117
|
-
/** Agentic Search 활성화 — AI 가 쿼리를 자동 생성하여 다중 검색 수행 */
|
|
7118
|
-
agentic?: boolean;
|
|
7119
|
-
/**
|
|
7120
|
-
* metadata 기반 필터 (옵셔널). 키 형식 `metadata.<path>` 또는 raw key.
|
|
7121
|
-
* 값에 `AUTH_MEMBER_ID_TOKEN` 사용 시 서버가 인증된 AppMember ID 로 치환.
|
|
7122
|
-
* AppMember JWT 컨텍스트가 있으면 서버가 추가로 metadata.user_id 강제 필터를 AND.
|
|
7123
|
-
*/
|
|
7124
|
-
where?: Record<string, unknown>;
|
|
7125
5194
|
}
|
|
7126
5195
|
interface KnowledgeSearchResult {
|
|
7127
5196
|
chunk_id: string;
|
|
@@ -7137,634 +5206,124 @@ interface KnowledgeSearchResponse {
|
|
|
7137
5206
|
query: string;
|
|
7138
5207
|
results: KnowledgeSearchResult[];
|
|
7139
5208
|
total: number;
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
5209
|
+
}
|
|
5210
|
+
interface ChatRequest {
|
|
5211
|
+
message: string;
|
|
5212
|
+
top_k?: number;
|
|
5213
|
+
model?: string;
|
|
5214
|
+
stream?: boolean;
|
|
5215
|
+
}
|
|
5216
|
+
interface ChatResponse {
|
|
5217
|
+
answer: string;
|
|
5218
|
+
sources: KnowledgeSearchResult[];
|
|
5219
|
+
model: string;
|
|
5220
|
+
token_used?: number;
|
|
7148
5221
|
}
|
|
7149
5222
|
|
|
7150
|
-
/**
|
|
7151
|
-
* `addDocumentFromFile` 입력 형식.
|
|
7152
|
-
*
|
|
7153
|
-
* - `File` (DOM) — 브라우저 `<input type="file">` 결과를 그대로 사용. name / type 이 자동 추출됨.
|
|
7154
|
-
* - `Blob` (DOM) — Blob.type 이 MIME 으로 사용됨 (없으면 서버 자동 추정).
|
|
7155
|
-
* - `{ data, mimeType?, name? }` — Node.js Buffer / Uint8Array. mimeType 명시 권장.
|
|
7156
|
-
*/
|
|
7157
|
-
type KnowledgeFileInput = File | Blob | {
|
|
7158
|
-
data: Uint8Array | ArrayBuffer;
|
|
7159
|
-
mimeType?: string;
|
|
7160
|
-
name?: string;
|
|
7161
|
-
};
|
|
7162
5223
|
/**
|
|
7163
5224
|
* Knowledge Base API
|
|
7164
5225
|
*
|
|
7165
|
-
*
|
|
5226
|
+
* RAG(Retrieval-Augmented Generation)를 위한 문서 저장 및 검색 API.
|
|
7166
5227
|
* 문서를 업로드하면 자동으로 청킹되어 키워드 기반 검색이 가능합니다.
|
|
7167
5228
|
*
|
|
7168
|
-
* ## 사용자별 격리 (다중 사용자 RAG 시나리오)
|
|
7169
|
-
*
|
|
7170
|
-
* `Authorization: Bearer <appmember-jwt>` 를 함께 보내면 서버가:
|
|
7171
|
-
* - 검색 결과를 본인 문서 (metadata.user_id == member_id) 로 제한
|
|
7172
|
-
* - addDocument 시 metadata.user_id 자동 태깅
|
|
7173
|
-
* - listDocuments / deleteDocument 도 본인 자료만 노출
|
|
7174
|
-
*
|
|
7175
5229
|
* @example
|
|
7176
5230
|
* ```typescript
|
|
7177
|
-
* const cb = new ConnectBase({
|
|
5231
|
+
* const cb = new ConnectBase({ apiKey: 'your-api-key' })
|
|
7178
5232
|
*
|
|
7179
5233
|
* // 텍스트 문서 추가
|
|
7180
5234
|
* await cb.knowledge.addDocument('kb-id', {
|
|
7181
5235
|
* name: '환불 정책',
|
|
7182
5236
|
* source_type: 'text',
|
|
7183
|
-
* content: '환불은 구매 후 7일 이내에 가능합니다...'
|
|
7184
|
-
* })
|
|
7185
|
-
*
|
|
7186
|
-
* // 문서 검색
|
|
7187
|
-
* const results = await cb.knowledge.search('kb-id', {
|
|
7188
|
-
* query: '환불 정책',
|
|
7189
|
-
* top_k: 5
|
|
7190
|
-
* })
|
|
7191
|
-
*
|
|
7192
|
-
* // 사용자별 격리 + 추가 필터 (AppMember JWT 가 같이 와야 함)
|
|
7193
|
-
* const results = await cb.knowledge.search('kb-id', {
|
|
7194
|
-
* query: '내 메모',
|
|
7195
|
-
* where: { 'metadata.tag': 'work' },
|
|
7196
|
-
* })
|
|
7197
|
-
* ```
|
|
7198
|
-
*/
|
|
7199
|
-
declare class KnowledgeAPI {
|
|
7200
|
-
private http;
|
|
7201
|
-
constructor(http: HttpClient);
|
|
7202
|
-
/**
|
|
7203
|
-
* 문서 추가
|
|
7204
|
-
*
|
|
7205
|
-
* 지식 베이스에 새 문서를 추가합니다. 텍스트 소스인 경우 즉시 처리됩니다.
|
|
7206
|
-
*
|
|
7207
|
-
* @param kbID - 지식 베이스 ID
|
|
7208
|
-
* @param data - 문서 생성 요청
|
|
7209
|
-
* @returns 생성된 문서 정보
|
|
7210
|
-
*
|
|
7211
|
-
* @example
|
|
7212
|
-
* ```typescript
|
|
7213
|
-
* // 텍스트 문서
|
|
7214
|
-
* const doc = await cb.knowledge.addDocument('kb-id', {
|
|
7215
|
-
* name: 'FAQ',
|
|
7216
|
-
* source_type: 'text',
|
|
7217
|
-
* content: '자주 묻는 질문들...'
|
|
7218
|
-
* })
|
|
7219
|
-
*
|
|
7220
|
-
* // URL에서 가져오기
|
|
7221
|
-
* const doc2 = await cb.knowledge.addDocument('kb-id', {
|
|
7222
|
-
* name: '도움말',
|
|
7223
|
-
* source_type: 'url',
|
|
7224
|
-
* source_url: 'https://example.com/help.html'
|
|
7225
|
-
* })
|
|
7226
|
-
*
|
|
7227
|
-
* // external_id 로 idempotent 동기화 (빌드 스크립트 등)
|
|
7228
|
-
* // 같은 external_id 로 다시 호출하면 기존 문서를 교체한다 (문서 id 유지).
|
|
7229
|
-
* await cb.knowledge.addDocument('kb-id', {
|
|
7230
|
-
* name: '블로그: 제목',
|
|
7231
|
-
* source_type: 'text',
|
|
7232
|
-
* content: '...',
|
|
7233
|
-
* external_id: 'blog/my-post-slug',
|
|
7234
|
-
* })
|
|
7235
|
-
* ```
|
|
7236
|
-
*/
|
|
7237
|
-
addDocument(kbID: string, data: CreateDocumentRequest): Promise<DocumentResponse>;
|
|
7238
|
-
/**
|
|
7239
|
-
* 문서 수정 (update/upsert)
|
|
7240
|
-
*
|
|
7241
|
-
* 기존 문서의 내용·이름·메타데이터를 교체합니다. **문서 id 는 그대로 유지**되므로
|
|
7242
|
-
* 검색 결과의 `document_id` 를 외부에서 참조(인용·캐시)해도 편집 후 깨지지 않습니다.
|
|
7243
|
-
* 보낸 필드만 교체되며, 내용/이름/메타데이터가 실제로 바뀌면 자동으로 재청킹·재색인됩니다.
|
|
7244
|
-
*
|
|
7245
|
-
* @param kbID - 지식 베이스 ID
|
|
7246
|
-
* @param docID - 문서 ID
|
|
7247
|
-
* @param data - 변경할 필드 (생략한 필드는 변경 없음)
|
|
7248
|
-
* @returns 수정된 문서 정보
|
|
7249
|
-
*
|
|
7250
|
-
* @example
|
|
7251
|
-
* ```typescript
|
|
7252
|
-
* // 내용만 교체 — document_id 는 그대로
|
|
7253
|
-
* const doc = await cb.knowledge.updateDocument('kb-id', 'doc-id', {
|
|
7254
|
-
* content: '갱신된 환불 정책...',
|
|
7255
|
-
* })
|
|
7256
|
-
*
|
|
7257
|
-
* // 이름 + 메타데이터 교체
|
|
7258
|
-
* await cb.knowledge.updateDocument('kb-id', 'doc-id', {
|
|
7259
|
-
* name: 'FAQ (2026)',
|
|
7260
|
-
* metadata: { tag: 'faq', updated: '2026-05' },
|
|
7261
|
-
* })
|
|
7262
|
-
* ```
|
|
7263
|
-
*/
|
|
7264
|
-
updateDocument(kbID: string, docID: string, data: UpdateDocumentRequest): Promise<DocumentResponse>;
|
|
7265
|
-
/**
|
|
7266
|
-
* 파일로 문서 수정 (PDF / DOCX / text 파일 재업로드).
|
|
7267
|
-
*
|
|
7268
|
-
* [`addDocumentFromFile`](#addDocumentFromFile) 의 update 버전. 문서 id 는 유지됩니다.
|
|
7269
|
-
*
|
|
7270
|
-
* @param kbID - Knowledge Base ID
|
|
7271
|
-
* @param docID - 문서 ID
|
|
7272
|
-
* @param file - 새 파일. `File` (DOM) / `Blob` / `{ data, mimeType, name }` (Node) 모두 가능
|
|
7273
|
-
* @param options - name / metadata 오버라이드
|
|
7274
|
-
* @returns 수정된 문서 정보
|
|
7275
|
-
*/
|
|
7276
|
-
updateDocumentFromFile(kbID: string, docID: string, file: KnowledgeFileInput, options?: {
|
|
7277
|
-
name?: string;
|
|
7278
|
-
metadata?: Record<string, unknown>;
|
|
7279
|
-
}): Promise<DocumentResponse>;
|
|
7280
|
-
/**
|
|
7281
|
-
* 파일을 KB 에 추가 (PDF / DOCX / text 파일).
|
|
7282
|
-
*
|
|
7283
|
-
* 브라우저에서 `<input type="file">` 로 받은 `File` 또는 `Blob` 을 그대로 넘기면 SDK 가
|
|
7284
|
-
* base64 로 인코딩 + MIME 추정 후 서버에 보낸다. 서버는 PDF / DOCX / text 류를 자동
|
|
7285
|
-
* 텍스트 추출하여 기존 청킹·인덱싱 파이프라인을 태운다.
|
|
7286
|
-
*
|
|
7287
|
-
* 지원 MIME (2026-05 기준):
|
|
7288
|
-
* - `application/pdf` (텍스트 PDF — 스캔 이미지 PDF 는 미지원)
|
|
7289
|
-
* - `application/vnd.openxmlformats-officedocument.wordprocessingml.document` (DOCX)
|
|
7290
|
-
* - `text/*` (plain / markdown / csv / html)
|
|
7291
|
-
* - `application/json`
|
|
7292
|
-
*
|
|
7293
|
-
* 비지원 MIME (이미지 OCR / 한글 HWP / XLSX 등) 은 향후 추가될 예정 — 현재는 명시적 에러.
|
|
7294
|
-
*
|
|
7295
|
-
* 파일 크기 상한: 50MB (원본 바이너리 기준).
|
|
7296
|
-
*
|
|
7297
|
-
* @param kbID - Knowledge Base ID
|
|
7298
|
-
* @param file - 업로드할 파일. `File` (DOM) / `Blob` / `{ data, mimeType, name }` (Node) 모두 가능
|
|
7299
|
-
* @param options - name 오버라이드 + metadata
|
|
7300
|
-
* @returns 생성된 문서 정보 (서버에서 status='processing' → 청킹 완료 후 'ready')
|
|
7301
|
-
*
|
|
7302
|
-
* @example
|
|
7303
|
-
* ```typescript
|
|
7304
|
-
* // 브라우저: <input type="file"> 로 받은 File
|
|
7305
|
-
* const file = event.target.files[0]
|
|
7306
|
-
* const doc = await cb.knowledge.addDocumentFromFile('kb-id', file, {
|
|
7307
|
-
* metadata: { tag: 'manual' }
|
|
7308
|
-
* })
|
|
7309
|
-
*
|
|
7310
|
-
* // Node.js: fs.readFileSync 로 읽은 Buffer
|
|
7311
|
-
* import { readFileSync } from 'node:fs'
|
|
7312
|
-
* const data = readFileSync('./report.pdf')
|
|
7313
|
-
* const doc = await cb.knowledge.addDocumentFromFile('kb-id', {
|
|
7314
|
-
* data,
|
|
7315
|
-
* mimeType: 'application/pdf',
|
|
7316
|
-
* name: 'report.pdf',
|
|
7317
|
-
* })
|
|
7318
|
-
* ```
|
|
7319
|
-
*/
|
|
7320
|
-
addDocumentFromFile(kbID: string, file: KnowledgeFileInput, options?: {
|
|
7321
|
-
name?: string;
|
|
7322
|
-
metadata?: Record<string, unknown>;
|
|
7323
|
-
}): Promise<DocumentResponse>;
|
|
7324
|
-
/**
|
|
7325
|
-
* 문서 목록 조회
|
|
7326
|
-
*
|
|
7327
|
-
* @param kbID - 지식 베이스 ID
|
|
7328
|
-
* @returns 문서 목록
|
|
7329
|
-
*/
|
|
7330
|
-
listDocuments(kbID: string): Promise<ListDocumentsResponse>;
|
|
7331
|
-
/**
|
|
7332
|
-
* 문서 삭제
|
|
7333
|
-
*
|
|
7334
|
-
* 문서와 관련된 모든 청크도 함께 삭제됩니다.
|
|
7335
|
-
*
|
|
7336
|
-
* @param kbID - 지식 베이스 ID
|
|
7337
|
-
* @param docID - 문서 ID
|
|
7338
|
-
*/
|
|
7339
|
-
deleteDocument(kbID: string, docID: string): Promise<void>;
|
|
7340
|
-
/**
|
|
7341
|
-
* 문서 검색
|
|
7342
|
-
*
|
|
7343
|
-
* 키워드 기반으로 관련 문서 청크를 검색합니다.
|
|
7344
|
-
* 제목, 내용, 키워드 필드에서 매칭되며 점수 기반으로 정렬됩니다.
|
|
7345
|
-
*
|
|
7346
|
-
* @param kbID - 지식 베이스 ID
|
|
7347
|
-
* @param request - 검색 요청
|
|
7348
|
-
* @returns 검색 결과
|
|
7349
|
-
*
|
|
7350
|
-
* @example
|
|
7351
|
-
* ```typescript
|
|
7352
|
-
* const results = await cb.knowledge.search('kb-id', {
|
|
7353
|
-
* query: '환불 신청 방법',
|
|
7354
|
-
* top_k: 5 // 상위 5개 결과
|
|
7355
|
-
* })
|
|
7356
|
-
*
|
|
7357
|
-
* for (const result of results.results) {
|
|
7358
|
-
* console.log(`[${result.score}] ${result.title}`)
|
|
7359
|
-
* console.log(result.content)
|
|
7360
|
-
* }
|
|
7361
|
-
* ```
|
|
7362
|
-
*/
|
|
7363
|
-
search(kbID: string, request: KnowledgeSearchRequest): Promise<KnowledgeSearchResponse>;
|
|
7364
|
-
/**
|
|
7365
|
-
* 문서 검색 (GET 방식)
|
|
7366
|
-
*
|
|
7367
|
-
* 쿼리 파라미터로 검색합니다.
|
|
7368
|
-
*
|
|
7369
|
-
* @param kbID - 지식 베이스 ID
|
|
7370
|
-
* @param query - 검색 쿼리
|
|
7371
|
-
* @param topK - 반환할 결과 수 (기본값: 지식 베이스 설정)
|
|
7372
|
-
*/
|
|
7373
|
-
searchGet(kbID: string, query: string, topK?: number): Promise<KnowledgeSearchResponse>;
|
|
7374
|
-
}
|
|
7375
|
-
|
|
7376
|
-
interface AIMessage {
|
|
7377
|
-
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
7378
|
-
content: string;
|
|
7379
|
-
toolCalls?: AIToolCall[];
|
|
7380
|
-
toolCallId?: string;
|
|
7381
|
-
}
|
|
7382
|
-
interface AIToolCall {
|
|
7383
|
-
id: string;
|
|
7384
|
-
name: string;
|
|
7385
|
-
arguments: Record<string, unknown>;
|
|
7386
|
-
}
|
|
7387
|
-
interface AITool {
|
|
7388
|
-
name: string;
|
|
7389
|
-
description: string;
|
|
7390
|
-
inputSchema: Record<string, unknown>;
|
|
7391
|
-
}
|
|
7392
|
-
interface AIChatRequest {
|
|
7393
|
-
messages: AIMessage[];
|
|
7394
|
-
maxTokens?: number;
|
|
7395
|
-
temperature?: number;
|
|
7396
|
-
topP?: number;
|
|
7397
|
-
provider?: string;
|
|
7398
|
-
model?: string;
|
|
7399
|
-
tools?: AITool[];
|
|
7400
|
-
appId?: string;
|
|
7401
|
-
knowledgeBaseId?: string;
|
|
7402
|
-
topK?: number;
|
|
7403
|
-
agentic?: boolean;
|
|
7404
|
-
toolGroupId?: string;
|
|
7405
|
-
}
|
|
7406
|
-
interface AIToolEvent {
|
|
7407
|
-
type: 'tool_start' | 'tool_end' | 'heartbeat';
|
|
7408
|
-
name?: string;
|
|
7409
|
-
toolCallId?: string;
|
|
7410
|
-
arguments?: Record<string, unknown>;
|
|
7411
|
-
result?: string;
|
|
7412
|
-
success?: boolean;
|
|
7413
|
-
durationMs?: number;
|
|
7414
|
-
}
|
|
7415
|
-
interface AISource {
|
|
7416
|
-
chunkId: string;
|
|
7417
|
-
documentId: string;
|
|
7418
|
-
documentName: string;
|
|
7419
|
-
content: string;
|
|
7420
|
-
score: number;
|
|
7421
|
-
}
|
|
7422
|
-
interface AIChatResponse {
|
|
7423
|
-
content: string;
|
|
7424
|
-
/**
|
|
7425
|
-
* 추론 모델(Qwen3 reasoning, OpenAI o-series, DeepSeek-R1 등)의 사고 과정.
|
|
7426
|
-
* 최종 답변(`content`)과 분리되어 제공됩니다. 추론 모델이 아니면 비어 있습니다.
|
|
7427
|
-
*/
|
|
7428
|
-
reasoning?: string;
|
|
7429
|
-
finishReason?: string;
|
|
7430
|
-
usage?: {
|
|
7431
|
-
promptTokens: number;
|
|
7432
|
-
completionTokens: number;
|
|
7433
|
-
totalTokens: number;
|
|
7434
|
-
};
|
|
7435
|
-
provider: string;
|
|
7436
|
-
model: string;
|
|
7437
|
-
toolCalls?: AIToolCall[];
|
|
7438
|
-
sources?: AISource[];
|
|
7439
|
-
}
|
|
7440
|
-
/**
|
|
7441
|
-
* Agentic 검색의 한 단계 진행 상황. `chatStream({ agentic: true })` 시
|
|
7442
|
-
* `onSearching` 콜백으로 실시간 전달되어 "검색 중…" 진행 UI 를 구성할 수 있다.
|
|
7443
|
-
*/
|
|
7444
|
-
interface AgenticSearchProgress {
|
|
7445
|
-
/** 'query_generation' = 검색어 생성 중, 'searching' = 검색 실행 중, 'complete' = 검색 종료 */
|
|
7446
|
-
phase: 'query_generation' | 'searching' | 'complete';
|
|
7447
|
-
/** 검색 라운드 (1~2). agentic 은 결과가 부족하면 2라운드까지 수행. */
|
|
7448
|
-
round?: number;
|
|
7449
|
-
/** 이 라운드에서 생성된 검색 쿼리들 (phase='searching'). */
|
|
7450
|
-
queries?: string[];
|
|
7451
|
-
/** phase='complete': 누적 결과 청크 수. */
|
|
7452
|
-
results?: number;
|
|
7453
|
-
/** phase='complete': 총 검색 라운드 수. 0 은 폴백(단일 키워드 검색)을 의미. */
|
|
7454
|
-
rounds?: number;
|
|
7455
|
-
}
|
|
7456
|
-
interface AIStreamChunk {
|
|
7457
|
-
type?: 'sources' | 'token' | 'searching' | 'tool_start' | 'tool_end' | 'heartbeat';
|
|
7458
|
-
content: string;
|
|
7459
|
-
/**
|
|
7460
|
-
* 추론 모델의 사고 과정 델타. 추론 구간의 청크는 `content`가 비어 있고
|
|
7461
|
-
* `reasoning`만 채워져 전달됩니다.
|
|
7462
|
-
*/
|
|
7463
|
-
reasoning?: string;
|
|
7464
|
-
finishReason?: string;
|
|
7465
|
-
done: boolean;
|
|
7466
|
-
toolCalls?: AIToolCall[];
|
|
7467
|
-
sources?: AISource[];
|
|
7468
|
-
name?: string;
|
|
7469
|
-
toolCallId?: string;
|
|
7470
|
-
arguments?: Record<string, unknown>;
|
|
7471
|
-
result?: string;
|
|
7472
|
-
success?: boolean;
|
|
7473
|
-
durationMs?: number;
|
|
7474
|
-
searching?: AgenticSearchProgress;
|
|
7475
|
-
}
|
|
7476
|
-
|
|
7477
|
-
/**
|
|
7478
|
-
* AI API
|
|
7479
|
-
*
|
|
7480
|
-
* AI 채팅 및 AI 데이터베이스 연동 API.
|
|
7481
|
-
* AI 데이터베이스 ID를 지정하면 문서 검색 후 컨텍스트를 포함하여 응답합니다.
|
|
7482
|
-
*
|
|
7483
|
-
* @example
|
|
7484
|
-
* ```typescript
|
|
7485
|
-
* const cb = new ConnectBase({ publicKey: 'your-public-key' })
|
|
7486
|
-
*
|
|
7487
|
-
* // 일반 AI 채팅
|
|
7488
|
-
* const response = await cb.ai.chat({
|
|
7489
|
-
* messages: [{ role: 'user', content: '안녕하세요' }],
|
|
7490
|
-
* provider: 'gemini'
|
|
7491
|
-
* })
|
|
7492
|
-
*
|
|
7493
|
-
* // AI 데이터베이스 연동 채팅
|
|
7494
|
-
* const ragResponse = await cb.ai.chat({
|
|
7495
|
-
* messages: [{ role: 'user', content: '환불 정책이 어떻게 되나요?' }],
|
|
7496
|
-
* knowledgeBaseId: 'kb-id',
|
|
7497
|
-
* topK: 5
|
|
7498
|
-
* })
|
|
7499
|
-
* ```
|
|
7500
|
-
*/
|
|
7501
|
-
declare class AIAPI {
|
|
7502
|
-
private http;
|
|
7503
|
-
constructor(http: HttpClient);
|
|
7504
|
-
/**
|
|
7505
|
-
* AI 채팅 (동기)
|
|
7506
|
-
*/
|
|
7507
|
-
chat(request: AIChatRequest): Promise<AIChatResponse>;
|
|
7508
|
-
/**
|
|
7509
|
-
* AI 채팅 스트리밍 (SSE)
|
|
7510
|
-
*
|
|
7511
|
-
* @example
|
|
7512
|
-
* ```typescript
|
|
7513
|
-
* await cb.ai.chatStream({
|
|
7514
|
-
* messages: [{ role: 'user', content: '안녕하세요' }],
|
|
7515
|
-
* knowledgeBaseId: 'kb-id',
|
|
7516
|
-
* }, {
|
|
7517
|
-
* onSources: (sources) => console.log('참조:', sources),
|
|
7518
|
-
* onReasoning: (reasoning) => process.stdout.write(reasoning),
|
|
7519
|
-
* onToken: (content) => process.stdout.write(content),
|
|
7520
|
-
* onDone: () => console.log('\\n완료'),
|
|
7521
|
-
* onError: (error) => console.error('에러:', error)
|
|
7522
|
-
* })
|
|
7523
|
-
* ```
|
|
7524
|
-
*/
|
|
7525
|
-
chatStream(request: AIChatRequest, callbacks: {
|
|
7526
|
-
onSources?: (sources: AISource[]) => void;
|
|
7527
|
-
/**
|
|
7528
|
-
* 추론 모델의 사고 과정 델타. 추론 모델(Qwen3 reasoning, o-series 등)을
|
|
7529
|
-
* 사용할 때만 호출되며, 최종 답변은 `onToken`으로 별도 전달됩니다.
|
|
7530
|
-
*/
|
|
7531
|
-
onReasoning?: (reasoning: string) => void;
|
|
7532
|
-
onToken?: (content: string) => void;
|
|
7533
|
-
onToolEvent?: (event: AIToolEvent) => void;
|
|
7534
|
-
/**
|
|
7535
|
-
* Agentic 검색(`agentic: true`) 진행 상황. agentic 검색이 검색어를
|
|
7536
|
-
* 생성하고 다중 라운드로 검색하는 각 단계마다 호출되어, "검색 중…"
|
|
7537
|
-
* 진행 UI 를 구성할 수 있다. agentic 미사용 시 호출되지 않는다.
|
|
7538
|
-
*/
|
|
7539
|
-
onSearching?: (progress: AgenticSearchProgress) => void;
|
|
7540
|
-
onDone?: () => void;
|
|
7541
|
-
onError?: (error: string) => void;
|
|
7542
|
-
}): Promise<void>;
|
|
7543
|
-
}
|
|
7544
|
-
|
|
7545
|
-
/**
|
|
7546
|
-
* EndpointAPI — 사용자 PC GPU 모델을 `cb_pk_*` 한 키로 호출하는 dumb pipe.
|
|
7547
|
-
*
|
|
7548
|
-
* 핵심 비전: ConnectBase 는 **모델·API·워크플로우를 알지 않는다**. 사용자가 자기 PC 에서
|
|
7549
|
-
* 자기 모델을 띄우고 자기 API 를 정한다. SDK 는 라벨 → tunnel 매핑만 알고 페이로드
|
|
7550
|
-
* 그대로 forward.
|
|
7551
|
-
*
|
|
7552
|
-
* @example ComfyUI 호출
|
|
7553
|
-
* ```typescript
|
|
7554
|
-
* const cb = new ConnectBase({ publicKey: "cb_pk_..." })
|
|
7555
|
-
* const res = await cb.endpoint.call("comfyui-main", {
|
|
7556
|
-
* method: "POST",
|
|
7557
|
-
* path: "/prompt",
|
|
7558
|
-
* body: JSON.stringify({
|
|
7559
|
-
* prompt: {
|
|
7560
|
-
* // ComfyUI 노드 그래프
|
|
7561
|
-
* },
|
|
7562
|
-
* }),
|
|
7563
|
-
* headers: { "Content-Type": "application/json" },
|
|
7564
|
-
* })
|
|
7565
|
-
* const data = await res.json()
|
|
7566
|
-
* ```
|
|
7567
|
-
*
|
|
7568
|
-
* @example 스트리밍 응답 (SSE / chunked)
|
|
7569
|
-
* ```typescript
|
|
7570
|
-
* const res = await cb.endpoint.call("vllm-local", {
|
|
7571
|
-
* method: "POST",
|
|
7572
|
-
* path: "/v1/chat/completions",
|
|
7573
|
-
* body: JSON.stringify({
|
|
7574
|
-
* stream: true,
|
|
7575
|
-
* messages: [
|
|
7576
|
-
* // { role, content }
|
|
7577
|
-
* ],
|
|
7578
|
-
* }),
|
|
7579
|
-
* headers: { "Content-Type": "application/json" },
|
|
5237
|
+
* content: '환불은 구매 후 7일 이내에 가능합니다...'
|
|
7580
5238
|
* })
|
|
7581
|
-
* if (!res.body) throw new Error("no stream")
|
|
7582
|
-
* const reader = res.body.getReader()
|
|
7583
|
-
* while (true) {
|
|
7584
|
-
* const { done, value } = await reader.read()
|
|
7585
|
-
* if (done) break
|
|
7586
|
-
* // value 는 Uint8Array — 디코드 후 처리
|
|
7587
|
-
* }
|
|
7588
|
-
* ```
|
|
7589
5239
|
*
|
|
7590
|
-
*
|
|
7591
|
-
*
|
|
7592
|
-
*
|
|
7593
|
-
*
|
|
7594
|
-
* const res = await cb.endpoint.call("hunyuan-laptop", {
|
|
7595
|
-
* method: "POST",
|
|
7596
|
-
* path: "/generate",
|
|
7597
|
-
* signal: ctrl.signal,
|
|
7598
|
-
* body: JSON.stringify({
|
|
7599
|
-
* // 모델 입력
|
|
7600
|
-
* }),
|
|
5240
|
+
* // 문서 검색
|
|
5241
|
+
* const results = await cb.knowledge.search('kb-id', {
|
|
5242
|
+
* query: '환불 정책',
|
|
5243
|
+
* top_k: 5
|
|
7601
5244
|
* })
|
|
7602
5245
|
* ```
|
|
7603
5246
|
*/
|
|
7604
|
-
declare class
|
|
5247
|
+
declare class KnowledgeAPI {
|
|
7605
5248
|
private http;
|
|
7606
5249
|
constructor(http: HttpClient);
|
|
7607
5250
|
/**
|
|
7608
|
-
*
|
|
7609
|
-
*
|
|
7610
|
-
* 동작:
|
|
7611
|
-
* - URL 조립: `${baseUrl}/v1/proxy/${label}${path}`
|
|
7612
|
-
* - X-Public-Key 헤더 자동 주입 (호출자가 명시하면 그 값 우선)
|
|
7613
|
-
* - body / method / 추가 헤더 / signal 그대로 전달
|
|
7614
|
-
* - 응답 그대로 반환 (Response 객체) — 스트리밍은 res.body 로 read
|
|
5251
|
+
* 문서 추가
|
|
7615
5252
|
*
|
|
7616
|
-
*
|
|
7617
|
-
* @param init - fetch() 의 RequestInit + path. path 는 사용자 모델 서버의 엔드포인트 경로 (예: "/prompt", "/v1/chat/completions").
|
|
7618
|
-
*/
|
|
7619
|
-
call(label: string, init: EndpointCallInit): Promise<Response>;
|
|
7620
|
-
/**
|
|
7621
|
-
* 라벨 + path 의 최종 호출 URL `${baseUrl}/v1/proxy/${label}${path}` 을 조립해서
|
|
7622
|
-
* 반환. URL 을 다른 시스템 (Service Worker, 백엔드 워커, 로깅) 에 넘기거나
|
|
7623
|
-
* 디버깅 용도일 때 사용.
|
|
5253
|
+
* 지식 베이스에 새 문서를 추가합니다. 텍스트 소스인 경우 즉시 처리됩니다.
|
|
7624
5254
|
*
|
|
7625
|
-
*
|
|
7626
|
-
*
|
|
7627
|
-
*
|
|
7628
|
-
* 제공하지 않습니다. 그런 경우엔 `call()` 로 받아서 Blob URL 로 변환하세요.
|
|
5255
|
+
* @param kbID - 지식 베이스 ID
|
|
5256
|
+
* @param data - 문서 생성 요청
|
|
5257
|
+
* @returns 생성된 문서 정보
|
|
7629
5258
|
*
|
|
7630
|
-
* @example
|
|
5259
|
+
* @example
|
|
7631
5260
|
* ```typescript
|
|
7632
|
-
*
|
|
7633
|
-
*
|
|
7634
|
-
*
|
|
5261
|
+
* // 텍스트 문서
|
|
5262
|
+
* const doc = await cb.knowledge.addDocument('kb-id', {
|
|
5263
|
+
* name: 'FAQ',
|
|
5264
|
+
* source_type: 'text',
|
|
5265
|
+
* content: '자주 묻는 질문들...'
|
|
7635
5266
|
* })
|
|
7636
|
-
* ```
|
|
7637
5267
|
*
|
|
7638
|
-
*
|
|
7639
|
-
*
|
|
7640
|
-
*
|
|
7641
|
-
*
|
|
5268
|
+
* // URL에서 가져오기
|
|
5269
|
+
* const doc2 = await cb.knowledge.addDocument('kb-id', {
|
|
5270
|
+
* name: '도움말',
|
|
5271
|
+
* source_type: 'url',
|
|
5272
|
+
* source_url: 'https://example.com/help.html'
|
|
7642
5273
|
* })
|
|
7643
|
-
* img.src = URL.createObjectURL(await res.blob())
|
|
7644
|
-
* // 나중에 URL.revokeObjectURL(img.src)
|
|
7645
5274
|
* ```
|
|
7646
5275
|
*/
|
|
7647
|
-
|
|
5276
|
+
addDocument(kbID: string, data: CreateDocumentRequest): Promise<DocumentResponse>;
|
|
7648
5277
|
/**
|
|
7649
|
-
*
|
|
7650
|
-
* ComfyUI `/history/{id}`, A1111 `/sdapi/v1/progress`, 자체 큐 API 처럼
|
|
7651
|
-
* "작업 제출 → 폴링" 패턴을 한 줄로 처리하기 위한 헬퍼.
|
|
5278
|
+
* 문서 목록 조회
|
|
7652
5279
|
*
|
|
7653
|
-
*
|
|
7654
|
-
*
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
*
|
|
5280
|
+
* @param kbID - 지식 베이스 ID
|
|
5281
|
+
* @returns 문서 목록
|
|
5282
|
+
*/
|
|
5283
|
+
listDocuments(kbID: string): Promise<ListDocumentsResponse>;
|
|
5284
|
+
/**
|
|
5285
|
+
* 문서 삭제
|
|
7659
5286
|
*
|
|
7660
|
-
*
|
|
7661
|
-
* `res.clone().json()` 형태로 안전하게 파싱한 뒤 호출자에게 전달.
|
|
5287
|
+
* 문서와 관련된 모든 청크도 함께 삭제됩니다.
|
|
7662
5288
|
*
|
|
7663
|
-
* @
|
|
7664
|
-
*
|
|
7665
|
-
* type Hist = Record<string, { outputs: Record<string, { images?: { filename: string }[] }> }>
|
|
7666
|
-
*
|
|
7667
|
-
* const filename = await cb.endpoint.pollUntil<string>(
|
|
7668
|
-
* "comfyui-main",
|
|
7669
|
-
* { path: `/history/${promptId}` },
|
|
7670
|
-
* (data: Hist) => {
|
|
7671
|
-
* const entry = data[promptId]
|
|
7672
|
-
* if (!entry) return undefined // 아직 큐에 있음
|
|
7673
|
-
* for (const out of Object.values(entry.outputs)) {
|
|
7674
|
-
* const img = out.images?.[0]
|
|
7675
|
-
* if (img) return img.filename
|
|
7676
|
-
* }
|
|
7677
|
-
* return undefined
|
|
7678
|
-
* },
|
|
7679
|
-
* { intervalMs: 1000, timeoutMs: 5 * 60_000 },
|
|
7680
|
-
* )
|
|
7681
|
-
* ```
|
|
5289
|
+
* @param kbID - 지식 베이스 ID
|
|
5290
|
+
* @param docID - 문서 ID
|
|
7682
5291
|
*/
|
|
5292
|
+
deleteDocument(kbID: string, docID: string): Promise<void>;
|
|
7683
5293
|
/**
|
|
7684
|
-
*
|
|
7685
|
-
* `/ws` event channel) through the ConnectBase proxy.
|
|
5294
|
+
* 문서 검색
|
|
7686
5295
|
*
|
|
7687
|
-
*
|
|
7688
|
-
*
|
|
7689
|
-
* solves that by:
|
|
7690
|
-
* 1. POSTing to `/v1/proxy/<label>/ws-ticket` (with `X-Public-Key`)
|
|
7691
|
-
* to obtain a single-use 30s token,
|
|
7692
|
-
* 2. Opening `wss://<base>/v1/proxy/<label><path>?ticket=<token>&...`,
|
|
7693
|
-
* 3. Returning the established `WebSocket` to the caller.
|
|
5296
|
+
* 키워드 기반으로 관련 문서 청크를 검색합니다.
|
|
5297
|
+
* 제목, 내용, 키워드 필드에서 매칭되며 점수 기반으로 정렬됩니다.
|
|
7694
5298
|
*
|
|
7695
|
-
*
|
|
7696
|
-
*
|
|
5299
|
+
* @param kbID - 지식 베이스 ID
|
|
5300
|
+
* @param request - 검색 요청
|
|
5301
|
+
* @returns 검색 결과
|
|
7697
5302
|
*
|
|
7698
|
-
* @example
|
|
7699
|
-
* ```
|
|
7700
|
-
* const
|
|
7701
|
-
*
|
|
7702
|
-
*
|
|
5303
|
+
* @example
|
|
5304
|
+
* ```typescript
|
|
5305
|
+
* const results = await cb.knowledge.search('kb-id', {
|
|
5306
|
+
* query: '환불 신청 방법',
|
|
5307
|
+
* top_k: 5 // 상위 5개 결과
|
|
7703
5308
|
* })
|
|
7704
|
-
*
|
|
7705
|
-
*
|
|
7706
|
-
*
|
|
7707
|
-
*
|
|
7708
|
-
* }
|
|
5309
|
+
*
|
|
5310
|
+
* for (const result of results.results) {
|
|
5311
|
+
* console.log(`[${result.score}] ${result.title}`)
|
|
5312
|
+
* console.log(result.content)
|
|
7709
5313
|
* }
|
|
7710
5314
|
* ```
|
|
7711
5315
|
*/
|
|
7712
|
-
|
|
7713
|
-
pollUntil<T>(label: string, init: EndpointCallInit, predicate: (body: any, res: Response) => T | undefined | Promise<T | undefined>, opts?: PollUntilOptions): Promise<T>;
|
|
7714
|
-
}
|
|
7715
|
-
/**
|
|
7716
|
-
* EndpointAPI.call 의 init 인자.
|
|
7717
|
-
*
|
|
7718
|
-
* 표준 RequestInit 와 거의 동일하지만 `path` 가 필수 (URL 은 SDK 가 조립).
|
|
7719
|
-
*/
|
|
7720
|
-
interface EndpointCallInit {
|
|
7721
|
-
/**
|
|
7722
|
-
* 사용자 모델 서버의 엔드포인트 경로. 반드시 `/` 로 시작.
|
|
7723
|
-
* 예: `"/prompt"`, `"/v1/chat/completions"`, `"/sdapi/v1/txt2img"`.
|
|
7724
|
-
*/
|
|
7725
|
-
path: string;
|
|
7726
|
-
/** HTTP 메서드 (기본: GET). */
|
|
7727
|
-
method?: string;
|
|
7728
|
-
/** 추가 요청 헤더. Content-Type / Authorization 등 사용자 모델 서버가 요구하는 것 그대로. */
|
|
7729
|
-
headers?: HeadersInit;
|
|
7730
|
-
/** 요청 본문. Blob / ArrayBuffer / FormData / string / ReadableStream 모두 지원. */
|
|
7731
|
-
body?: BodyInit | null;
|
|
7732
|
-
/** 취소 신호. */
|
|
7733
|
-
signal?: AbortSignal;
|
|
7734
|
-
}
|
|
7735
|
-
/**
|
|
7736
|
-
* EndpointAPI.connectWebSocket 옵션.
|
|
7737
|
-
*/
|
|
7738
|
-
interface ConnectWebSocketOptions {
|
|
7739
|
-
/**
|
|
7740
|
-
* 사용자 모델 서버의 WebSocket 엔드포인트 경로. `/` 로 시작 (기본 `/`).
|
|
7741
|
-
* 예: `/ws`, `/socket`.
|
|
7742
|
-
*/
|
|
7743
|
-
path?: string;
|
|
7744
|
-
/** 추가 query 파라미터 (ticket 은 자동 주입). */
|
|
7745
|
-
query?: Record<string, string>;
|
|
7746
|
-
/** WebSocket subprotocols (Sec-WebSocket-Protocol 헤더). */
|
|
7747
|
-
protocols?: string | string[];
|
|
7748
|
-
/** Abort 시 ws.close(1000) 호출. */
|
|
7749
|
-
signal?: AbortSignal;
|
|
7750
|
-
}
|
|
7751
|
-
/**
|
|
7752
|
-
* EndpointAPI.pollUntil 옵션.
|
|
7753
|
-
*/
|
|
7754
|
-
interface PollUntilOptions {
|
|
7755
|
-
/** 폴링 간격 (ms). 기본 1500. */
|
|
7756
|
-
intervalMs?: number;
|
|
7757
|
-
/** 전체 timeout (ms). 기본 300000 (5분). */
|
|
7758
|
-
timeoutMs?: number;
|
|
5316
|
+
search(kbID: string, request: KnowledgeSearchRequest): Promise<KnowledgeSearchResponse>;
|
|
7759
5317
|
/**
|
|
7760
|
-
*
|
|
7761
|
-
*
|
|
7762
|
-
*
|
|
7763
|
-
*
|
|
5318
|
+
* 문서 검색 (GET 방식)
|
|
5319
|
+
*
|
|
5320
|
+
* 쿼리 파라미터로 검색합니다.
|
|
5321
|
+
*
|
|
5322
|
+
* @param kbID - 지식 베이스 ID
|
|
5323
|
+
* @param query - 검색 쿼리
|
|
5324
|
+
* @param topK - 반환할 결과 수 (기본값: 지식 베이스 설정)
|
|
7764
5325
|
*/
|
|
7765
|
-
|
|
7766
|
-
/** 외부 취소 신호. abort 시 즉시 reject. */
|
|
7767
|
-
signal?: AbortSignal;
|
|
5326
|
+
searchGet(kbID: string, query: string, topK?: number): Promise<KnowledgeSearchResponse>;
|
|
7768
5327
|
}
|
|
7769
5328
|
|
|
7770
5329
|
interface PublishMessageRequest {
|
|
@@ -7830,7 +5389,7 @@ interface QueueInfoResponse {
|
|
|
7830
5389
|
*
|
|
7831
5390
|
* @example
|
|
7832
5391
|
* ```typescript
|
|
7833
|
-
* const cb = new ConnectBase({
|
|
5392
|
+
* const cb = new ConnectBase({ apiKey: 'your-api-key' })
|
|
7834
5393
|
*
|
|
7835
5394
|
* // 메시지 발행
|
|
7836
5395
|
* await cb.queue.publish('queue-id', {
|
|
@@ -7879,334 +5438,6 @@ declare class QueueAPI {
|
|
|
7879
5438
|
getInfo(queueID: string): Promise<QueueInfoResponse>;
|
|
7880
5439
|
}
|
|
7881
5440
|
|
|
7882
|
-
/**
|
|
7883
|
-
* 사용자 제보 (end-user issue) — 카테고리.
|
|
7884
|
-
*
|
|
7885
|
-
* - `bug` 버그 리포트
|
|
7886
|
-
* - `question` 질문/문의
|
|
7887
|
-
* - `feature_request` 기능 요청
|
|
7888
|
-
* - `incident` 긴급 장애
|
|
7889
|
-
* - `other` 그 외
|
|
7890
|
-
*/
|
|
7891
|
-
type SupportIssueCategory = 'bug' | 'question' | 'feature_request' | 'incident' | 'other';
|
|
7892
|
-
/**
|
|
7893
|
-
* 제보 발행 요청 본문.
|
|
7894
|
-
*/
|
|
7895
|
-
interface ReportIssueRequest {
|
|
7896
|
-
/** 제목 (최대 200자) */
|
|
7897
|
-
title: string;
|
|
7898
|
-
/** 본문 (최대 16KB, 마크다운) */
|
|
7899
|
-
body: string;
|
|
7900
|
-
/** 카테고리. 기본값 `other`. AI 가 자동 보정해 줌. */
|
|
7901
|
-
category?: SupportIssueCategory;
|
|
7902
|
-
/** 자유 컨텍스트 (페이지 URL, 앱 버전, trace_id 등) */
|
|
7903
|
-
metadata?: Record<string, unknown>;
|
|
7904
|
-
/**
|
|
7905
|
-
* 익명 발행 시 회신 받을 이메일 (선택).
|
|
7906
|
-
* 로그인된 사용자면 무시되고 AppMember 정보로 대체.
|
|
7907
|
-
*/
|
|
7908
|
-
anonymousEmail?: string;
|
|
7909
|
-
/**
|
|
7910
|
-
* Google reCAPTCHA v3 토큰. 익명 발행 + 운영자가 reCAPTCHA 활성화한 앱은 권장.
|
|
7911
|
-
* 미주입 시 score=0 으로 처리 — 거부될 수 있음.
|
|
7912
|
-
*/
|
|
7913
|
-
recaptchaToken?: string;
|
|
7914
|
-
}
|
|
7915
|
-
/**
|
|
7916
|
-
* 제보 발행 응답. 보안상 최소 정보만 (id + status + created_at).
|
|
7917
|
-
*/
|
|
7918
|
-
interface ReportIssueResponse {
|
|
7919
|
-
id: string;
|
|
7920
|
-
status: 'open';
|
|
7921
|
-
created_at: string;
|
|
7922
|
-
}
|
|
7923
|
-
/**
|
|
7924
|
-
* Cross-app 위임 user 발행 요청 본문.
|
|
7925
|
-
*
|
|
7926
|
-
* 일반 `reportIssue` 와 다른 점:
|
|
7927
|
-
* - target_app 이 호출자(source_app) 와 다름 (다른 앱에 보내는 위임 제보)
|
|
7928
|
-
* - SDK 인증 컨텍스트(publicKey/secretKey) 가 아닌 cross-app OAuth Bearer access_token 사용
|
|
7929
|
-
* - reporter_member_id 는 access_token 의 end_user_id claim 에서 자동 추출 (body 로 전달 불가)
|
|
7930
|
-
*/
|
|
7931
|
-
interface ReportIssueOnBehalfOfUserRequest {
|
|
7932
|
-
/** 수신 앱(target) 의 ID. OAuth token 의 audience(`app:<uuid>`) 와 일치해야 함. */
|
|
7933
|
-
targetAppId: string;
|
|
7934
|
-
/**
|
|
7935
|
-
* Cross-app OAuth access_token (`authorization_code` grant — user binding 필수).
|
|
7936
|
-
* scope 에 `issue:report:on-behalf-of-user` 가 포함돼야 한다.
|
|
7937
|
-
* `client_credentials` grant 토큰은 401 `delegated_user_required` 로 거부됨.
|
|
7938
|
-
*/
|
|
7939
|
-
accessToken: string;
|
|
7940
|
-
/** 제목 (최대 200자) */
|
|
7941
|
-
title: string;
|
|
7942
|
-
/** 본문 (최대 16KB, 마크다운) */
|
|
7943
|
-
body: string;
|
|
7944
|
-
/** 카테고리. 기본값 `other`. AI triage 가 보정. */
|
|
7945
|
-
category?: SupportIssueCategory;
|
|
7946
|
-
/** 자유 컨텍스트 (페이지 URL, request_id 등). PII 직접 포함 금지. */
|
|
7947
|
-
metadata?: Record<string, unknown>;
|
|
7948
|
-
}
|
|
7949
|
-
/**
|
|
7950
|
-
* Support API — 사용자 제보 (end-user issue) 발행.
|
|
7951
|
-
*
|
|
7952
|
-
* 사용자가 앱 운영자에게 직접 버그/질문/요청을 보내는 채널. AppMember JWT 가 있으면
|
|
7953
|
-
* 강 신뢰로 회신 가능, 없으면 익명 발행 (reCAPTCHA 권장).
|
|
7954
|
-
*
|
|
7955
|
-
* 발행된 이슈는 운영자 콘솔의 inbox 에 들어가며, AI 가 자동으로 요약/긴급도/카테고리를
|
|
7956
|
-
* 분류해줘 운영자/AI 의 처리 효율을 높여준다.
|
|
7957
|
-
*
|
|
7958
|
-
* @example 로그인 사용자가 버그 리포트
|
|
7959
|
-
* ```typescript
|
|
7960
|
-
* // (cb.auth.signIn 으로 로그인 완료된 상태)
|
|
7961
|
-
* await cb.support.reportIssue({
|
|
7962
|
-
* title: "결제 화면이 멈춰요",
|
|
7963
|
-
* body: "결제 버튼 클릭 후 로딩이 끝나지 않습니다.",
|
|
7964
|
-
* category: "bug",
|
|
7965
|
-
* metadata: { pageUrl: window.location.href, browser: navigator.userAgent },
|
|
7966
|
-
* })
|
|
7967
|
-
* ```
|
|
7968
|
-
*
|
|
7969
|
-
* @example 익명 + reCAPTCHA v3
|
|
7970
|
-
* ```typescript
|
|
7971
|
-
* // window.grecaptcha 는 reCAPTCHA v3 site script 로드 후 전역으로 노출됨
|
|
7972
|
-
* const grecaptcha = (globalThis as any).grecaptcha
|
|
7973
|
-
* const SITE_KEY = "your-recaptcha-site-key"
|
|
7974
|
-
* const token = await grecaptcha.execute(SITE_KEY, { action: 'report_issue' })
|
|
7975
|
-
* await cb.support.reportIssue({
|
|
7976
|
-
* title: "버그 제보",
|
|
7977
|
-
* body: "익명으로 제보합니다",
|
|
7978
|
-
* category: "question",
|
|
7979
|
-
* anonymousEmail: "user@example.com",
|
|
7980
|
-
* recaptchaToken: token,
|
|
7981
|
-
* })
|
|
7982
|
-
* ```
|
|
7983
|
-
*/
|
|
7984
|
-
declare class SupportAPI {
|
|
7985
|
-
private http;
|
|
7986
|
-
constructor(http: HttpClient);
|
|
7987
|
-
/**
|
|
7988
|
-
* 앱 운영자에게 이슈/문의/요청을 발행한다.
|
|
7989
|
-
*
|
|
7990
|
-
* 로그인된 사용자(AppMember)면 신뢰 등급이 높고 reporter_member_id 가 자동으로 채워진다.
|
|
7991
|
-
* 익명 발행도 가능하나 운영자가 reCAPTCHA 를 활성화한 경우 `recaptchaToken` 이 권장된다.
|
|
7992
|
-
*
|
|
7993
|
-
* @returns 발행된 이슈 id + 초기 status (`open`) + 생성 시각.
|
|
7994
|
-
* @throws ApiError — 본문 길이 초과 / 쿼터 초과(429) / reCAPTCHA 거부(403) 등.
|
|
7995
|
-
*/
|
|
7996
|
-
reportIssue(req: ReportIssueRequest): Promise<ReportIssueResponse>;
|
|
7997
|
-
/**
|
|
7998
|
-
* 다른 앱(target) 에 자기 사용자(end-user) 명의로 cross-app 위임 이슈를 발행한다.
|
|
7999
|
-
*
|
|
8000
|
-
* **사용 시나리오**: source_app(예: Makers) 의 backend 가 OAuth `authorization_code` grant 로
|
|
8001
|
-
* 발급받은 사용자 access_token 을 사용해, target_app(예: ai-tool) 에게 "Makers user A 가 보낸"
|
|
8002
|
-
* 이슈로 제보. target 측 콘솔 inbox 에는 `reporter_kind=user` + `reporter_app_id=Makers` 로 표시.
|
|
8003
|
-
*
|
|
8004
|
-
* 본 메서드는 SDK 의 publicKey/secretKey 인증 컨텍스트를 사용하지 않고, 호출자가 명시적으로 전달한
|
|
8005
|
-
* cross-app OAuth Bearer access_token 만 사용 (server-to-server 위임 흐름).
|
|
8006
|
-
*
|
|
8007
|
-
* @param req - 발행 본문
|
|
8008
|
-
* @param req.targetAppId - 수신 앱 ID (= OAuth token 의 audience `app:<uuid>` 와 일치해야 함)
|
|
8009
|
-
* @param req.accessToken - source_app 이 발급받은 cross-app OAuth access_token (authorization_code grant)
|
|
8010
|
-
*
|
|
8011
|
-
* @throws ApiError 401 — `delegated_user_required`: access_token 이 client_credentials grant
|
|
8012
|
-
* @throws ApiError 403 — `trust_chain_violation`: source_app 이 target_app 의 cross-app provider 로 등록되지 않음
|
|
8013
|
-
* @throws ApiError 403 — `insufficient_scope`: token 에 `issue:report:on-behalf-of-user` 미포함
|
|
8014
|
-
*
|
|
8015
|
-
* @example Makers backend → ai-tool 에 사용자 명의 제보
|
|
8016
|
-
* ```typescript
|
|
8017
|
-
* await cb.support.reportIssueOnBehalfOfUser({
|
|
8018
|
-
* targetAppId: 'ai-tool-uuid',
|
|
8019
|
-
* accessToken: makersUserAccessToken, // authorization_code grant 토큰
|
|
8020
|
-
* title: '생성 실패',
|
|
8021
|
-
* body: 'prompt X 가 5분째 응답 없음',
|
|
8022
|
-
* category: 'bug',
|
|
8023
|
-
* metadata: { prompt_id: 'p_42' },
|
|
8024
|
-
* })
|
|
8025
|
-
* ```
|
|
8026
|
-
*/
|
|
8027
|
-
reportIssueOnBehalfOfUser(req: ReportIssueOnBehalfOfUserRequest): Promise<ReportIssueResponse>;
|
|
8028
|
-
/**
|
|
8029
|
-
* ConnectBase 플랫폼 자체 버그/요청/문의를 발행한다.
|
|
8030
|
-
*
|
|
8031
|
-
* `reportIssue` 와 다른 점: target 이 앱 운영자가 아닌 **ConnectBase 운영팀**.
|
|
8032
|
-
* SDK 가 자체 버그를 던지거나, 결제/문서/플랫폼 동작이 이상할 때 사용.
|
|
8033
|
-
*
|
|
8034
|
-
* 자동 첨부 (opt-out 가능):
|
|
8035
|
-
* - SDK 버전 + 플랫폼 (web/node)
|
|
8036
|
-
* - 마지막 N(20)개 API 호출 breadcrumb (PII strip 후)
|
|
8037
|
-
* - error 객체의 stack trace (sanitize)
|
|
8038
|
-
*
|
|
8039
|
-
* @example SDK 가 throw 한 에러를 자동 첨부해서 발행
|
|
8040
|
-
* ```typescript
|
|
8041
|
-
* try {
|
|
8042
|
-
* await cb.functions.invoke('foo', {})
|
|
8043
|
-
* } catch (err) {
|
|
8044
|
-
* await cb.support.reportPlatformBug({
|
|
8045
|
-
* title: 'functions.invoke 가 504 만 반환',
|
|
8046
|
-
* body: '같은 인자로 5분 째 504. 콘솔에선 정상.',
|
|
8047
|
-
* category: 'sdk',
|
|
8048
|
-
* severity: 'high',
|
|
8049
|
-
* error: err as Error,
|
|
8050
|
-
* })
|
|
8051
|
-
* }
|
|
8052
|
-
* ```
|
|
8053
|
-
*/
|
|
8054
|
-
reportPlatformBug(req: ReportPlatformBugRequest): Promise<ReportPlatformBugResponse>;
|
|
8055
|
-
/** 디버깅용: 마지막 N개 API 호출 breadcrumb. PII 제거 후 저장돼있다. */
|
|
8056
|
-
getRecentApiCalls(): RecentApiCall[];
|
|
8057
|
-
/** breadcrumb buffer 비우기 (사용자 명시적 요청 / 프라이버시). */
|
|
8058
|
-
clearRecentApiCalls(): void;
|
|
8059
|
-
/**
|
|
8060
|
-
* Platform issue 의 reply thread 조회.
|
|
8061
|
-
*
|
|
8062
|
-
* 본인이 발행한 issue 만 조회 가능 (server-side ownership guard). admin 의 internal 메모는 응답 제외.
|
|
8063
|
-
*
|
|
8064
|
-
* @param issueId - `reportPlatformBug` 가 반환한 id
|
|
8065
|
-
* @throws ApiError 404 — 본인 issue 가 아니거나 존재하지 않음
|
|
8066
|
-
*/
|
|
8067
|
-
listPlatformIssueReplies(issueId: string): Promise<PlatformIssueReply[]>;
|
|
8068
|
-
/**
|
|
8069
|
-
* Platform issue 에 follow-up reply 작성.
|
|
8070
|
-
*
|
|
8071
|
-
* 단말 상태(resolved/wontfix/duplicate) issue 는 reply 거부 — 새 issue 발행 권장.
|
|
8072
|
-
*/
|
|
8073
|
-
replyToPlatformIssue(issueId: string, body: string): Promise<PlatformIssueReply>;
|
|
8074
|
-
/**
|
|
8075
|
-
* 본인이 발행한 platform issue 의 처리 진행 상황을 단건 조회.
|
|
8076
|
-
*
|
|
8077
|
-
* AI 가 "내가 발행한 이슈 처리됐어?" 를 폴링하는 표준 경로. status / resolution_note /
|
|
8078
|
-
* external_links 로 ConnectBase 운영팀의 처리 상태를 확인.
|
|
8079
|
-
*
|
|
8080
|
-
* @throws ApiError 404 — 본인 issue 가 아니거나 존재하지 않음
|
|
8081
|
-
*/
|
|
8082
|
-
getPlatformIssue(issueId: string): Promise<PlatformIssueDetail>;
|
|
8083
|
-
/**
|
|
8084
|
-
* 본인 app 으로 발행한 platform issue 목록 (cursor 페이지네이션).
|
|
8085
|
-
*
|
|
8086
|
-
* status/severity/category 필터 + `since_updated_at` 으로 미해결만 폴링하는 사용 패턴 권장:
|
|
8087
|
-
*
|
|
8088
|
-
* ```typescript
|
|
8089
|
-
* const { issues } = await cb.support.listMyPlatformIssues({ status: ['open', 'triaged', 'in_progress'] })
|
|
8090
|
-
* ```
|
|
8091
|
-
*/
|
|
8092
|
-
listMyPlatformIssues(opts?: ListMyPlatformIssuesOptions): Promise<PlatformIssueListPage>;
|
|
8093
|
-
}
|
|
8094
|
-
/**
|
|
8095
|
-
* ConnectBase 플랫폼 이슈 카테고리.
|
|
8096
|
-
*/
|
|
8097
|
-
type PlatformIssueCategory = 'bug' | 'feature_request' | 'sdk' | 'billing' | 'security' | 'performance' | 'docs' | 'other';
|
|
8098
|
-
type PlatformIssueSeverity = 'low' | 'medium' | 'high' | 'critical';
|
|
8099
|
-
interface ReportPlatformBugRequest {
|
|
8100
|
-
/** 제목 (≤200) */
|
|
8101
|
-
title: string;
|
|
8102
|
-
/** 본문 (≤16KB, markdown) */
|
|
8103
|
-
body: string;
|
|
8104
|
-
/** 카테고리. 기본 `other`. 운영자가 admin 콘솔에서 조정 가능. */
|
|
8105
|
-
category?: PlatformIssueCategory;
|
|
8106
|
-
/** 긴급도. 기본 `medium`. 운영자가 admin 콘솔에서 조정 가능. */
|
|
8107
|
-
severity?: PlatformIssueSeverity;
|
|
8108
|
-
/** AppMember 가 없는 경우 회신용 이메일. */
|
|
8109
|
-
reporterEmail?: string;
|
|
8110
|
-
/** 익명 발행 시 reCAPTCHA v3 토큰 (운영팀이 RECAPTCHA_SECRET 설정한 경우). */
|
|
8111
|
-
recaptchaToken?: string;
|
|
8112
|
-
/** 자유 컨텍스트 (페이지 URL, request_id 등). PII 직접 포함 금지 — 호출자 책임. */
|
|
8113
|
-
metadata?: Record<string, unknown>;
|
|
8114
|
-
/**
|
|
8115
|
-
* 자동 컨텍스트 첨부 on/off (기본 true).
|
|
8116
|
-
* false 로 설정하면 SDK 버전/플랫폼/breadcrumb/stack 모두 미첨부.
|
|
8117
|
-
*/
|
|
8118
|
-
attachAutomaticContext?: boolean;
|
|
8119
|
-
/**
|
|
8120
|
-
* 에러 객체. .stack 을 sanitize 후 자동 첨부.
|
|
8121
|
-
* stackTrace 와 둘 중 하나만 — error 가 우선.
|
|
8122
|
-
*/
|
|
8123
|
-
error?: Error;
|
|
8124
|
-
/** 직접 작성한 stack trace (≤32KB, SDK 가 sanitize). */
|
|
8125
|
-
stackTrace?: string;
|
|
8126
|
-
/** 호출자가 명시적으로 buffer 를 override (테스트/특수 케이스). */
|
|
8127
|
-
recentApiCalls?: RecentApiCall[];
|
|
8128
|
-
/** SDK 버전 override (자동 감지 실패 시). */
|
|
8129
|
-
sdkVersion?: string;
|
|
8130
|
-
/** SDK 플랫폼 override. */
|
|
8131
|
-
sdkPlatform?: 'web' | 'node' | 'unity' | 'godot' | 'unreal' | 'cli' | 'mcp' | 'other';
|
|
8132
|
-
/** 환경 (production/staging/development). 기본 unknown. */
|
|
8133
|
-
environment?: 'production' | 'staging' | 'development' | 'unknown';
|
|
8134
|
-
}
|
|
8135
|
-
interface ReportPlatformBugResponse {
|
|
8136
|
-
id: string;
|
|
8137
|
-
status: 'open';
|
|
8138
|
-
created_at: string;
|
|
8139
|
-
}
|
|
8140
|
-
/**
|
|
8141
|
-
* Platform issue thread 의 단일 reply.
|
|
8142
|
-
*
|
|
8143
|
-
* - `author_kind=admin`: ConnectBase 운영팀 응답
|
|
8144
|
-
* - `author_kind=user`: 본인이 작성
|
|
8145
|
-
* - `author_kind=system`: 자동 메시지 (상태 변경 알림 등)
|
|
8146
|
-
*/
|
|
8147
|
-
/**
|
|
8148
|
-
* Platform issue 의 처리 진행 상황 (reporter 시점).
|
|
8149
|
-
*
|
|
8150
|
-
* admin-only 필드(`assignee_user_id` 등) 는 server 가 redact.
|
|
8151
|
-
*
|
|
8152
|
-
* 주요 필드:
|
|
8153
|
-
* - `status` : `open` → `triaged` → `in_progress` → `resolved` | `wontfix` | `duplicate`
|
|
8154
|
-
* - `resolution_note` : 단말 상태 진입 시 ConnectBase 운영팀이 작성한 처리 결과 (markdown)
|
|
8155
|
-
* - `external_links` : 운영팀이 연결한 GitHub PR / Linear ticket 등
|
|
8156
|
-
* - `resolved_at` : `resolved`/`wontfix` 진입 시각 (해결됐는지 빠른 검사용)
|
|
8157
|
-
*/
|
|
8158
|
-
interface PlatformIssueDetail {
|
|
8159
|
-
id: string;
|
|
8160
|
-
reporter_kind: 'user' | 'app' | 'system';
|
|
8161
|
-
title: string;
|
|
8162
|
-
body: string;
|
|
8163
|
-
category: PlatformIssueCategory;
|
|
8164
|
-
severity: PlatformIssueSeverity;
|
|
8165
|
-
status: 'open' | 'triaged' | 'in_progress' | 'resolved' | 'wontfix' | 'duplicate';
|
|
8166
|
-
resolution_note?: string;
|
|
8167
|
-
sdk_version?: string;
|
|
8168
|
-
sdk_platform?: 'web' | 'node' | 'unity' | 'godot' | 'unreal' | 'cli' | 'mcp' | 'other';
|
|
8169
|
-
environment?: 'production' | 'staging' | 'development' | 'unknown';
|
|
8170
|
-
external_links?: Array<{
|
|
8171
|
-
kind: string;
|
|
8172
|
-
url: string;
|
|
8173
|
-
label?: string;
|
|
8174
|
-
}>;
|
|
8175
|
-
duplicate_of_id?: string;
|
|
8176
|
-
created_at: string;
|
|
8177
|
-
updated_at: string;
|
|
8178
|
-
resolved_at?: string;
|
|
8179
|
-
}
|
|
8180
|
-
/** `listMyPlatformIssues` 응답 페이지. */
|
|
8181
|
-
interface PlatformIssueListPage {
|
|
8182
|
-
issues: PlatformIssueDetail[];
|
|
8183
|
-
/** 다음 페이지 cursor. 빈 문자열/undefined 면 끝. */
|
|
8184
|
-
next_cursor?: string;
|
|
8185
|
-
}
|
|
8186
|
-
/** `listMyPlatformIssues` 옵션. */
|
|
8187
|
-
interface ListMyPlatformIssuesOptions {
|
|
8188
|
-
/** 다중 status 필터. 미지정 시 전체. 처리중만 보려면 `['open','triaged','in_progress']`. */
|
|
8189
|
-
status?: PlatformIssueDetail['status'][];
|
|
8190
|
-
severity?: PlatformIssueSeverity[];
|
|
8191
|
-
category?: PlatformIssueCategory[];
|
|
8192
|
-
/** RFC3339 timestamp — 이후 update 된 issue 만. polling 시 마지막 fetch 시각 전달. */
|
|
8193
|
-
sinceUpdatedAt?: string;
|
|
8194
|
-
/** 이전 페이지 응답의 `next_cursor`. */
|
|
8195
|
-
cursor?: string;
|
|
8196
|
-
/** 페이지 크기. 기본 50, 최대 200. */
|
|
8197
|
-
limit?: number;
|
|
8198
|
-
}
|
|
8199
|
-
interface PlatformIssueReply {
|
|
8200
|
-
id: string;
|
|
8201
|
-
issue_id: string;
|
|
8202
|
-
author_kind: 'admin' | 'user' | 'system';
|
|
8203
|
-
author_user_id?: string;
|
|
8204
|
-
author_member_id?: string;
|
|
8205
|
-
body: string;
|
|
8206
|
-
is_internal: boolean;
|
|
8207
|
-
created_at: string;
|
|
8208
|
-
}
|
|
8209
|
-
|
|
8210
5441
|
/**
|
|
8211
5442
|
* WebTransport-based Game Client
|
|
8212
5443
|
*
|
|
@@ -8253,8 +5484,6 @@ declare class GameRoomTransport {
|
|
|
8253
5484
|
private actionSequence;
|
|
8254
5485
|
private _roomId;
|
|
8255
5486
|
private _state;
|
|
8256
|
-
private _scriptName;
|
|
8257
|
-
private _scriptVersion;
|
|
8258
5487
|
private _isConnected;
|
|
8259
5488
|
private _connectionStatus;
|
|
8260
5489
|
private _lastError;
|
|
@@ -8281,10 +5510,6 @@ declare class GameRoomTransport {
|
|
|
8281
5510
|
* Connection status
|
|
8282
5511
|
*/
|
|
8283
5512
|
get isConnected(): boolean;
|
|
8284
|
-
/** Attached lua script 이름 — createRoom 이후 server 가 echo 한 값. */
|
|
8285
|
-
get scriptName(): string | null;
|
|
8286
|
-
/** Attached lua script 의 active version. */
|
|
8287
|
-
get scriptVersion(): number | null;
|
|
8288
5513
|
/**
|
|
8289
5514
|
* Connection state information
|
|
8290
5515
|
*/
|
|
@@ -8306,16 +5531,9 @@ declare class GameRoomTransport {
|
|
|
8306
5531
|
*/
|
|
8307
5532
|
disconnect(): void;
|
|
8308
5533
|
/**
|
|
8309
|
-
* Create a new room
|
|
8310
|
-
*
|
|
8311
|
-
* Attached script 메타가 필요하면 {@link createRoomDetailed} 또는 인스턴스 getter
|
|
8312
|
-
* (`transport.scriptName`, `transport.scriptVersion`) 를 사용.
|
|
5534
|
+
* Create a new room
|
|
8313
5535
|
*/
|
|
8314
5536
|
createRoom(config?: GameRoomConfig): Promise<GameState>;
|
|
8315
|
-
/**
|
|
8316
|
-
* Create a new room — server 가 attach 한 lua script 메타 함께 반환.
|
|
8317
|
-
*/
|
|
8318
|
-
createRoomDetailed(config?: GameRoomConfig): Promise<CreateRoomResult>;
|
|
8319
5537
|
/**
|
|
8320
5538
|
* Join an existing room
|
|
8321
5539
|
*/
|
|
@@ -8388,21 +5606,9 @@ interface ConnectBaseConfig {
|
|
|
8388
5606
|
*/
|
|
8389
5607
|
appId?: string;
|
|
8390
5608
|
/**
|
|
8391
|
-
*
|
|
8392
|
-
* 브라우저/클라이언트에서 사용. RLS(Row Level Security) 적용.
|
|
8393
|
-
*/
|
|
8394
|
-
publicKey?: string;
|
|
8395
|
-
/**
|
|
8396
|
-
* User Secret Key (`cb_sk_*` 형식, 사용자 프로필에서 발급).
|
|
8397
|
-
*
|
|
8398
|
-
* **SDK 의 앱 레벨 API (database, storage, function 등) 용 자격증명이 아닙니다.**
|
|
8399
|
-
* 앱 API 호출에는 `publicKey` 를 사용하세요. 앱 API 경로(`/v1/public/*`)는
|
|
8400
|
-
* Public Key(`cb_pk_*`) 만 허용하며, Secret Key 로 호출하면 서버가 401 을 반환합니다.
|
|
8401
|
-
*
|
|
8402
|
-
* 이 필드는 CLI (`connectbase tunnel`, `connectbase mcp`) 및 사용자 레벨 API 인증에
|
|
8403
|
-
* 사용됩니다. 서버 환경에서만 사용하고 절대 브라우저에 노출하지 마세요.
|
|
5609
|
+
* API Key (콘솔에서 발급)
|
|
8404
5610
|
*/
|
|
8405
|
-
|
|
5611
|
+
apiKey?: string;
|
|
8406
5612
|
/**
|
|
8407
5613
|
* 토큰이 갱신될 때 호출되는 콜백
|
|
8408
5614
|
*/
|
|
@@ -8420,7 +5626,7 @@ interface ConnectBaseConfig {
|
|
|
8420
5626
|
* @example
|
|
8421
5627
|
* ```typescript
|
|
8422
5628
|
* const cb = new ConnectBase({
|
|
8423
|
-
*
|
|
5629
|
+
* apiKey: 'your-api-key',
|
|
8424
5630
|
* onTokenExpired: () => {
|
|
8425
5631
|
* // 로그인 페이지로 리다이렉트
|
|
8426
5632
|
* window.location.href = '/login'
|
|
@@ -8429,64 +5635,10 @@ interface ConnectBaseConfig {
|
|
|
8429
5635
|
* ```
|
|
8430
5636
|
*/
|
|
8431
5637
|
onTokenExpired?: () => void;
|
|
8432
|
-
/**
|
|
8433
|
-
* `/v1/auth/re-issue` 의 일시적 실패 (5xx, 네트워크 오류, abort, 손상된 200 응답) 시 호출.
|
|
8434
|
-
*
|
|
8435
|
-
* 이 경우 토큰은 폐기되지 않으며 `onTokenExpired` 도 호출되지 않습니다 — 다음 호출에서
|
|
8436
|
-
* backoff 만료 후 자동 재시도. 사용자에게 "연결이 잠시 불안정합니다" 같은 비파괴적
|
|
8437
|
-
* 알림을 띄울 때 사용. permanent (refresh token 자체 무효) 와 분리하기 위함.
|
|
8438
|
-
*
|
|
8439
|
-
* @example
|
|
8440
|
-
* ```typescript
|
|
8441
|
-
* const cb = new ConnectBase({
|
|
8442
|
-
* publicKey: '...',
|
|
8443
|
-
* onTransientRefreshFailure: (err) => toast.warn('연결이 불안정합니다. 잠시 후 자동 복구됩니다.'),
|
|
8444
|
-
* onTokenExpired: () => { window.location.href = '/login' },
|
|
8445
|
-
* })
|
|
8446
|
-
* ```
|
|
8447
|
-
*/
|
|
8448
|
-
onTransientRefreshFailure?: (error: Error) => void;
|
|
8449
|
-
/**
|
|
8450
|
-
* 토큰 저장 방식.
|
|
8451
|
-
* - 'none' (기본·권장): access token 만 메모리. refresh token 은 서버 HttpOnly cookie 로
|
|
8452
|
-
* 보관되어 JS 가 접근할 수 없음 (XSS 시 탈취 불가). 새로고침 후에는 `autoRestoreSession`
|
|
8453
|
-
* (기본 true) 으로 cookie 만으로 자동 복구.
|
|
8454
|
-
* - 'sessionStorage': 탭 종료 시 삭제 (XSS 시 탭 세션 탈취 가능 — 콘솔 경고 출력)
|
|
8455
|
-
* - 'localStorage': 브라우저 종료 후에도 유지 (XSS 시 영구 탈취 가능 — 콘솔 경고 출력)
|
|
8456
|
-
* @default 'none'
|
|
8457
|
-
*/
|
|
8458
|
-
persistence?: TokenPersistence;
|
|
8459
|
-
/**
|
|
8460
|
-
* 새로고침/탭 재개 시 HttpOnly cookie 만으로 access token 을 자동 복구할지 여부.
|
|
8461
|
-
* 브라우저 환경에서 기본 true. cookie 가 없거나 만료되었으면 조용히 실패.
|
|
8462
|
-
*
|
|
8463
|
-
* cookie 가 없는 미로그인 상태에서 콘솔에 401 노이즈가 찍히지 않도록 silent 처리한다.
|
|
8464
|
-
*
|
|
8465
|
-
* @default true (브라우저), false (Node.js / RN)
|
|
8466
|
-
*/
|
|
8467
|
-
autoRestoreSession?: boolean;
|
|
8468
5638
|
/**
|
|
8469
5639
|
* 에러 트래커 설정
|
|
8470
5640
|
*/
|
|
8471
5641
|
errorTracker?: ErrorTrackerConfig;
|
|
8472
|
-
/**
|
|
8473
|
-
* 기본 요청 타임아웃(ms). 개별 호출의 `timeout` 이 지정되면 해당 값이 우선.
|
|
8474
|
-
* 기본값 30000ms. 0 또는 음수 지정 시 타임아웃 비활성화.
|
|
8475
|
-
*/
|
|
8476
|
-
requestTimeoutMs?: number;
|
|
8477
|
-
/**
|
|
8478
|
-
* 전역 에러 관찰자. 모든 `ApiError` / `AuthError` 발생 시 호출됩니다.
|
|
8479
|
-
* Sentry/Datadog 등 관측성 파이프라인과 연결하기 위한 훅.
|
|
8480
|
-
*
|
|
8481
|
-
* @example
|
|
8482
|
-
* ```ts
|
|
8483
|
-
* const cb = new ConnectBase({
|
|
8484
|
-
* publicKey: '...',
|
|
8485
|
-
* onError: (err) => Sentry.captureException(err),
|
|
8486
|
-
* })
|
|
8487
|
-
* ```
|
|
8488
|
-
*/
|
|
8489
|
-
onError?: (error: ApiError | AuthError) => void;
|
|
8490
5642
|
}
|
|
8491
5643
|
/**
|
|
8492
5644
|
* Connect Base SDK
|
|
@@ -8497,13 +5649,13 @@ interface ConnectBaseConfig {
|
|
|
8497
5649
|
*
|
|
8498
5650
|
* // 간단 초기화 (API Key만 필요)
|
|
8499
5651
|
* const cb = new ConnectBase({
|
|
8500
|
-
*
|
|
5652
|
+
* apiKey: 'your-api-key'
|
|
8501
5653
|
* })
|
|
8502
5654
|
*
|
|
8503
5655
|
* // 커스텀 서버 URL 사용 시
|
|
8504
5656
|
* const cb = new ConnectBase({
|
|
8505
5657
|
* baseUrl: 'https://your-server.com',
|
|
8506
|
-
*
|
|
5658
|
+
* apiKey: 'your-api-key'
|
|
8507
5659
|
* })
|
|
8508
5660
|
*
|
|
8509
5661
|
* // 데이터 조회
|
|
@@ -8537,10 +5689,9 @@ declare class ConnectBase {
|
|
|
8537
5689
|
*/
|
|
8538
5690
|
readonly storage: StorageAPI;
|
|
8539
5691
|
/**
|
|
8540
|
-
*
|
|
5692
|
+
* API Key 관리 API
|
|
8541
5693
|
*/
|
|
8542
|
-
readonly
|
|
8543
|
-
/**
|
|
5694
|
+
readonly apiKey: ApiKeyAPI;
|
|
8544
5695
|
/**
|
|
8545
5696
|
* 서버리스 함수 API
|
|
8546
5697
|
*/
|
|
@@ -8591,54 +5742,16 @@ declare class ConnectBase {
|
|
|
8591
5742
|
*/
|
|
8592
5743
|
readonly native: NativeAPI;
|
|
8593
5744
|
/**
|
|
8594
|
-
*
|
|
5745
|
+
* Knowledge Base API (RAG 문서 검색)
|
|
8595
5746
|
* 문서를 업로드하고 키워드 기반으로 검색하여 AI 챗봇을 구축할 수 있습니다.
|
|
8596
5747
|
*/
|
|
8597
5748
|
readonly knowledge: KnowledgeAPI;
|
|
8598
|
-
/**
|
|
8599
|
-
* AI API (채팅 + AI 데이터베이스 연동)
|
|
8600
|
-
* AI 채팅, AI 데이터베이스 문서 참조 응답, 스트리밍 지원.
|
|
8601
|
-
*/
|
|
8602
|
-
readonly ai: AIAPI;
|
|
8603
5749
|
/**
|
|
8604
5750
|
* Queue API (메시지 큐)
|
|
8605
5751
|
* NATS JetStream 기반 고신뢰 메시지 큐. 발행, 소비, Ack, Nack 지원.
|
|
8606
5752
|
*/
|
|
8607
5753
|
readonly queue: QueueAPI;
|
|
8608
|
-
/**
|
|
8609
|
-
* Analytics API (웹 분석)
|
|
8610
|
-
* 페이지뷰, 커스텀 이벤트, 세션 추적. GA4 수준의 웹 분석 제공.
|
|
8611
|
-
*/
|
|
8612
|
-
readonly analytics: AnalyticsAPI;
|
|
8613
|
-
/**
|
|
8614
|
-
* Endpoint API (로컬 모델 터널 dumb pipe)
|
|
8615
|
-
* 사용자 PC GPU 모델 (ComfyUI / A1111 / Hunyuan3D / 자체 FastAPI 등) 을 `cb_pk_*`
|
|
8616
|
-
* 한 키로 호출. 라벨로 라우팅, 페이로드/응답은 그대로 통과.
|
|
8617
|
-
*/
|
|
8618
|
-
readonly endpoint: EndpointAPI;
|
|
8619
|
-
/**
|
|
8620
|
-
* Support API (사용자 제보 / 이슈 큐)
|
|
8621
|
-
* 앱 사용자가 운영자에게 버그/질문/요청을 발행. AI 가 자동 분류/우선순위 처리.
|
|
8622
|
-
*/
|
|
8623
|
-
readonly support: SupportAPI;
|
|
8624
5754
|
constructor(config?: ConnectBaseConfig);
|
|
8625
|
-
/**
|
|
8626
|
-
* 현재 페이지가 OAuth 리다이렉트 콜백 페이지인지 판별.
|
|
8627
|
-
*
|
|
8628
|
-
* `?access_token=...&refresh_token=...` (legacy 토큰-in-URL 흐름) 또는
|
|
8629
|
-
* `?code=...` (OAUTH_CODE_ONLY 흐름) 또는 OAuth 에러 응답 (`?error=...&state=...`)
|
|
8630
|
-
* 패턴이면 true. 콜백 페이지에서 `autoRestoreSession` 을 건너뛰어 rotation race 를 피한다.
|
|
8631
|
-
*/
|
|
8632
|
-
private isOAuthCallbackUrl;
|
|
8633
|
-
/**
|
|
8634
|
-
* 새로고침/탭 재개 후 cookie 만으로 세션을 복원한다 (브라우저 전용).
|
|
8635
|
-
*
|
|
8636
|
-
* 일반적으로는 ConnectBase 생성 시 `autoRestoreSession: true` (기본값) 으로 자동 호출되지만,
|
|
8637
|
-
* 호출 결과를 await 해서 로그인 상태에 따라 다른 UI 를 그리고 싶다면 명시적으로 호출한다.
|
|
8638
|
-
*
|
|
8639
|
-
* @returns access token 복원 성공 시 true, 미로그인/cookie 만료 시 false
|
|
8640
|
-
*/
|
|
8641
|
-
restoreSession(): Promise<boolean>;
|
|
8642
5755
|
/**
|
|
8643
5756
|
* 수동으로 토큰 설정 (기존 토큰으로 세션 복원 시)
|
|
8644
5757
|
*/
|
|
@@ -8653,4 +5766,4 @@ declare class ConnectBase {
|
|
|
8653
5766
|
updateConfig(config: Partial<ConnectBaseConfig>): void;
|
|
8654
5767
|
}
|
|
8655
5768
|
|
|
8656
|
-
export {
|
|
5769
|
+
export { type AckMessagesRequest, type AdReportResponse, type AdReportSummary, AdsAPI, type AggregateResult, type AggregateStage, ApiError, type ApiKeyItem, type AppStatsResponse, type ArchivePolicy, type AtomicOperator, type AtomicOperatorType, AuthError, type AuthSettingsResponse, type BackupInfo, type BatchOperation, type BatchSetPageMetaRequest, type BillingCycle, type BillingKeyResponse, type BiometricInfo, type BiometricResult, type BulkCreateResponse, type BulkError, type CPUInfo, type CancelPaymentRequest, type CancelPaymentResponse, type CancelSubscriptionRequest, type CategoryInfo, type Channel, type ChannelMembership, type ChargeWithBillingKeyRequest, type ChargeWithBillingKeyResponse, type ChatMessage, type ChatRequest, type ChatResponse, type ClientMessage, type ColumnSchema, type CommentListResponse, type CompleteUploadRequest, type CompleteUploadResponse, type ConfirmBillingKeyRequest, type ConfirmPaymentRequest, type ConfirmPaymentResponse, ConnectBase, type ConnectBaseConfig, type ConnectedData, type ConnectionState, type ConsumeMessagesResponse, type ConsumeOptions, type CopyTableRequest, type CopyTableResponse, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateBackupRequest, type CreateChannelRequest, type CreateColumnRequest, type CreateDataRequest, type CreateDocumentRequest, type CreateFolderRequest, type CreateFolderResponse, type CreateGeoIndexRequest, type CreateIndexRequest, type CreateLobbyRequest, type CreatePlaylistRequest, type CreateRelationRequest, type CreateSearchIndexRequest, type CreateSecurityRuleRequest, type CreateSubscriptionRequest, type CreateTableRequest, type CreateTriggerRequest, type DailyReport, type DataItem, type DataType, type DatabaseChange, type DatabaseChangeMessage, type DatabaseChangeType, type DatabasePresenceState, type DatabaseRealtimeConnectOptions, type DatabaseRealtimeFilter, type DatabaseRealtimeHandlers, type DatabaseRealtimeSubscription, type DatabaseSnapshot, type DatabaseSnapshotMessage, type DatabaseSubscribeOptions, type DeleteWhereResponse, type DeviceInfo, type DocumentResponse, type EnabledProviderInfo, type EnabledProvidersResponse, type ErrorHandler, type ErrorMessage, type ErrorReport, type ErrorTrackerConfig, type ErrorType, type ExportDataRequest, type ExportDataResponse, type FetchApiKeysResponse, type FetchDataResponse, type FetchFilesResponse, type FileItem, type FileStats, GameAPI, type GameAction, type GameClientConfig, type GameConnectionState, type GameConnectionStatus, type GameDelta, type GameEventHandlers, type GamePlayer, GameRoom, type GameRoomConfig, type GameRoomInfo, GameRoomTransport, type GameServerMessage, type GameServerMessageType, type GameState, type GameTransportConfig, type GenerateUploadURLByPathRequest, type GenerateUploadURLRequest, type GenerateUploadURLResponse, type GeoIndex, type GeoNear, type GeoPoint, type GeoPolygon, type GeoQuery, type GeoResponse, type GeoResult, type GeoWithin, type GetAuthorizationURLResponse, type GetFileByPathResponse, type GoogleConnectionStatus, type GuestMemberSignInResponse, type HistoryResponse, type ICEServer, type ICEServersResponse, type ImageResult, type ImportDataRequest, type ImportDataResponse, type IndexAnalysis, type IndexRecommendation, type InitUploadResponse, type InvokeFunctionRequest, type InvokeFunctionResponse, type IssueBillingKeyRequest, type IssueBillingKeyResponse, type JoinQueueRequest, type JoinRoomRequest, type JoinRoomResponse, type KnowledgeSearchRequest, type KnowledgeSearchResponse, type KnowledgeSearchResult, type LifecyclePolicy, type ListBillingKeysResponse, type ListDocumentsResponse, type ListPageMetasOptions, type ListPageMetasResponse, type ListSubscriptionPaymentsRequest, type ListSubscriptionPaymentsResponse, type ListSubscriptionsRequest, type ListSubscriptionsResponse, type LobbyInfo, type LobbyInvite, type LobbyMember, type LobbyVisibility, type MatchmakingTicket, type MemberInfoResponse, type MemberSignInRequest, type MemberSignInResponse, type MemberSignUpRequest, type MemberSignUpResponse, type MembershipTier, type MemoryInfo, type MessageHandler, type MigrateDataRequest, type MigrateDataResponse, type MoveFileRequest, type NackMessageRequest, NativeAPI, type OAuthCallbackResponse, type OAuthProvider, type OpenDialogOptions, type OpenDialogResult, type PageMetaResponse, type PauseSubscriptionRequest, type PaymentDetail, type PaymentProvider, type PaymentStatus, type PeerInfo, type Platform, type PlayerEvent, type Playlist, type PlaylistItem, type PongMessage, type PopulateOption, type Position, type PreparePaymentRequest, type PreparePaymentResponse, type PresenceChangeHandler, type PresenceInfo, type PresenceSetOptions, type PresenceStatus, type PresenceStatusResult, type PublishBatchRequest, type PublishBatchResponse, type PublishMessageRequest, type PublishMessageResponse, type PushPlatform, type QualityProgress, type QueryOptions, type QueueInfoResponse, type QueueMessage, type ReadReceiptHandler, type ReadReceiptInfo, type RealtimeConnectOptions, type RealtimeMessage, type RegisterDeviceRequest, type RelationType, type RenameFileRequest, type RenameFileResponse, type RestoreBackupRequest, type RestoreBackupResponse, type RetentionPolicy, type RoomInfo, type RoomStats, type RoomsResponse, type SaveDialogOptions, type SaveDialogResult, type SearchIndex, type SearchOptions, type SearchResponse, type SearchResult, type SecurityRule, type SendOptions, type ServerMessage, type SetPageMetaRequest, type Shorts, type ShortsListResponse, type SignalingMessage, type SignalingMessageType, type SlowQueryInfo, type StateChange, type StateChangeHandler, type StreamDoneCallback, type StreamDoneData, type StreamErrorCallback, type StreamHandlers, type StreamMessage, type StreamOptions, type StreamSession, type StreamTokenCallback, type StreamURLResponse, type SubscribeOptions, type SubscribeTopicRequest, type SubscribedData, type Subscription, type SubscriptionPaymentResponse, type SubscriptionPaymentStatus, type SubscriptionResponse, type SubscriptionStatus, type SuperChat, type SystemInfo, type TTLConfig, type TableIndex, type TableRelation, type TableSchema, type TransactionRead, type TransactionWrite, type TranscodeStatus, type TransportType, type Trigger, type TriggerEvent, type TriggerHandlerType, type TypingChangeHandler, type TypingInfo, type UpdateApiKeyRequest, type UpdateApiKeyResponse, type UpdateBillingKeyRequest, type UpdateChannelRequest, type UpdateColumnRequest, type UpdateCustomDataRequest, type UpdateCustomDataResponse, type UpdateDataRequest, type UpdateLobbyRequest, type UpdateSecurityRuleRequest, type UpdateSubscriptionRequest, type UpdateTriggerRequest, type UpdateVideoRequest, type UploadByPathOptions, type UploadFileResponse, type UploadOptions, type UploadProgress, type VAPIDPublicKeyResponse, type ValidateResponse, type Video, type VideoComment, type VideoListOptions, type VideoListResponse, VideoProcessingError, type VideoQuality, type VideoStatus, type VideoVisibility, type WaitOptions, type WatchHistoryItem, type WebPushSubscription, type WebRTCConnectOptions, type WebRTCConnectionState, type WebRTCMode, type WhereCondition, type WhereOperator, ConnectBase as default, detectInAppBrowser, escapeToExternalBrowser, isWebTransportSupported };
|