connectbase-client 3.46.0 → 3.48.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/CHANGELOG.md +11 -0
- package/dist/connect-base.umd.js +4 -4
- package/dist/index.d.mts +227 -5
- package/dist/index.d.ts +227 -5
- package/dist/index.js +177 -5
- package/dist/index.mjs +176 -5
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -139,6 +139,9 @@ var HttpClient = class {
|
|
|
139
139
|
* 한 번 settle 되면 그 결과(메모리 적재 또는 미로그인)가 항상 반영되어 있다.
|
|
140
140
|
*/
|
|
141
141
|
this.bootRestorePromise = null;
|
|
142
|
+
// OAuth 콜백 부트스트랩처럼 세션 힌트 유무와 무관하게 첫 인증 호출이 반드시 기다려야
|
|
143
|
+
// 하는 boot promise 인지 여부 (setBootRestorePromise 의 alwaysAwait 옵션).
|
|
144
|
+
this.bootRestoreAlwaysAwait = false;
|
|
142
145
|
this.config = { ...config };
|
|
143
146
|
this.storageKey = this.buildStorageKey();
|
|
144
147
|
this.warnIfUnsafePersistence();
|
|
@@ -148,9 +151,14 @@ var HttpClient = class {
|
|
|
148
151
|
* 페이지 진입 시 fire-and-forget 으로 시작된 cookie 복구 promise 를 SDK 가 등록한다.
|
|
149
152
|
* 같은 promise 가 `prepareHeaders` 에서 await 되어, 첫 인증 호출이 cookie 복구
|
|
150
153
|
* 완료 후 발화한다.
|
|
154
|
+
*
|
|
155
|
+
* options.alwaysAwait=true 면 세션 힌트가 없어도 첫 인증 호출이 이 promise 를
|
|
156
|
+
* 기다린다 — OAuth 리다이렉트 콜백처럼 "이 부트 promise 가 곧 세션을 만든다"는 것이
|
|
157
|
+
* 확실한 흐름용 (일반 cookie 복구는 힌트 기반 fast-path 적용).
|
|
151
158
|
*/
|
|
152
|
-
setBootRestorePromise(p) {
|
|
159
|
+
setBootRestorePromise(p, options) {
|
|
153
160
|
this.bootRestorePromise = p.catch(() => false);
|
|
161
|
+
this.bootRestoreAlwaysAwait = options?.alwaysAwait === true;
|
|
154
162
|
}
|
|
155
163
|
/** 최근 호출 ring buffer 스냅샷 (시간순). */
|
|
156
164
|
getRecentCalls() {
|
|
@@ -179,11 +187,49 @@ var HttpClient = class {
|
|
|
179
187
|
this.config.accessToken = accessToken;
|
|
180
188
|
this.config.refreshToken = refreshToken;
|
|
181
189
|
this.persistTokens();
|
|
190
|
+
this.markSessionHint();
|
|
182
191
|
}
|
|
183
192
|
clearTokens() {
|
|
184
193
|
this.config.accessToken = void 0;
|
|
185
194
|
this.config.refreshToken = void 0;
|
|
186
195
|
this.removePersistedTokens();
|
|
196
|
+
this.clearSessionHint();
|
|
197
|
+
}
|
|
198
|
+
// ===== 세션 힌트 =====
|
|
199
|
+
//
|
|
200
|
+
// "이 origin 에서 이 앱으로 로그인한 적이 있다"는 boolean 마커 (토큰 아님 — 민감정보 없음).
|
|
201
|
+
// 부트 시 cookie 복구(`/v1/auth/re-issue`)를 첫 인증 호출이 기다릴지 판단하는 데 쓴다:
|
|
202
|
+
// - 힌트 있음 → 기존과 동일하게 대기 (로그인 세션의 첫 호출이 익명으로 나가는 것 방지).
|
|
203
|
+
// - 힌트 없음 → 대기 생략. 익명 방문자(공개 사이트 첫 방문 대부분)의 첫 조회가
|
|
204
|
+
// re-issue 왕복만큼 빨라진다. 복구 자체는 백그라운드로 계속 진행되므로, 드물게
|
|
205
|
+
// 힌트가 지워졌지만 cookie 세션이 살아있는 경우도 이후 호출부터 자동 회복된다.
|
|
206
|
+
//
|
|
207
|
+
// 세션을 만드는 모든 흐름(로그인/OAuth 콜백/토큰 refresh)이 setTokens 를 경유하므로
|
|
208
|
+
// 그곳에서 마킹하고, clearTokens(로그아웃)에서 지운다.
|
|
209
|
+
buildSessionHintKey() {
|
|
210
|
+
return `${this.buildStorageKey()}:has_session`;
|
|
211
|
+
}
|
|
212
|
+
markSessionHint() {
|
|
213
|
+
if (typeof window === "undefined") return;
|
|
214
|
+
try {
|
|
215
|
+
localStorage.setItem(this.buildSessionHintKey(), "1");
|
|
216
|
+
} catch {
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
clearSessionHint() {
|
|
220
|
+
if (typeof window === "undefined") return;
|
|
221
|
+
try {
|
|
222
|
+
localStorage.removeItem(this.buildSessionHintKey());
|
|
223
|
+
} catch {
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
hasSessionHint() {
|
|
227
|
+
if (typeof window === "undefined") return false;
|
|
228
|
+
try {
|
|
229
|
+
return localStorage.getItem(this.buildSessionHintKey()) === "1";
|
|
230
|
+
} catch {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
187
233
|
}
|
|
188
234
|
/**
|
|
189
235
|
* OAuth redirect callback 직후 호출되어 HttpOnly cookie 를 부트스트랩한다.
|
|
@@ -512,7 +558,7 @@ var HttpClient = class {
|
|
|
512
558
|
if (credential) {
|
|
513
559
|
headers.set("X-Public-Key", credential);
|
|
514
560
|
}
|
|
515
|
-
if (!config?.skipAuth && !this.config.accessToken && this.config.publicKey && typeof window !== "undefined" && this.bootRestorePromise) {
|
|
561
|
+
if (!config?.skipAuth && !this.config.accessToken && this.config.publicKey && typeof window !== "undefined" && this.bootRestorePromise && (this.bootRestoreAlwaysAwait || this.hasSessionHint())) {
|
|
516
562
|
try {
|
|
517
563
|
await this.bootRestorePromise;
|
|
518
564
|
} catch {
|
|
@@ -1222,6 +1268,7 @@ var DatabaseAPI = class {
|
|
|
1222
1268
|
const params = new URLSearchParams();
|
|
1223
1269
|
if (options?.limit) params.append("limit", options.limit.toString());
|
|
1224
1270
|
if (options?.offset) params.append("offset", options.offset.toString());
|
|
1271
|
+
if (options?.count === false) params.append("count", "false");
|
|
1225
1272
|
const queryString = params.toString();
|
|
1226
1273
|
const url = queryString ? `${prefix}/tables/${tableId}/data?${queryString}` : `${prefix}/tables/${tableId}/data`;
|
|
1227
1274
|
return this.http.get(url);
|
|
@@ -1240,7 +1287,8 @@ var DatabaseAPI = class {
|
|
|
1240
1287
|
limit: options.limit,
|
|
1241
1288
|
offset: options.offset,
|
|
1242
1289
|
select: options.select,
|
|
1243
|
-
exclude: options.exclude
|
|
1290
|
+
exclude: options.exclude,
|
|
1291
|
+
count: options.count
|
|
1244
1292
|
}
|
|
1245
1293
|
);
|
|
1246
1294
|
}
|
|
@@ -1404,7 +1452,8 @@ var DatabaseAPI = class {
|
|
|
1404
1452
|
offset: options.offset,
|
|
1405
1453
|
select: options.select,
|
|
1406
1454
|
exclude: options.exclude,
|
|
1407
|
-
populate: options.populate
|
|
1455
|
+
populate: options.populate,
|
|
1456
|
+
count: options.count
|
|
1408
1457
|
}
|
|
1409
1458
|
);
|
|
1410
1459
|
}
|
|
@@ -5403,6 +5452,38 @@ var PaymentAPI = class {
|
|
|
5403
5452
|
const prefix = this.getPublicPrefix();
|
|
5404
5453
|
return this.http.get(`${prefix}/payments/orders/${orderId}`);
|
|
5405
5454
|
}
|
|
5455
|
+
/**
|
|
5456
|
+
* 앱의 결제 내역 목록을 조회한다 (필터/페이지네이션 지원).
|
|
5457
|
+
*
|
|
5458
|
+
* 서버사이드 전용 — service_role(ctx.cbAdmin, management_scopes=["payment:read"]) 또는 콘솔 JWT
|
|
5459
|
+
* 인증이 필요하다. 재무 데이터이므로 Public Key(cb_pk_) 단독 브라우저 SDK 인스턴스로는 호출할 수
|
|
5460
|
+
* 없다. (다른 payment 메서드와 달리 /v1/public 이 아니라 앱 스코프 dual-auth 라우트를 쓴다.)
|
|
5461
|
+
*
|
|
5462
|
+
* @example
|
|
5463
|
+
* ```typescript
|
|
5464
|
+
* // 함수(service_role, management_scopes: ["payment:read"]) 안에서
|
|
5465
|
+
* const { payments, total } = await ctx.cbAdmin.payment.list(ctx.appId, { status: 'done', limit: 20 })
|
|
5466
|
+
* ```
|
|
5467
|
+
*/
|
|
5468
|
+
async list(appId, options) {
|
|
5469
|
+
if (this.http.hasPublicKey() && !this.http.hasJWT()) {
|
|
5470
|
+
throw new Error(
|
|
5471
|
+
'cb.payment.list() \uB294 \uCF58\uC194 JWT \uB610\uB294 service_role(ctx.cbAdmin, management_scopes: ["payment:read"]) \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. Public Key(cb_pk_) \uB2E8\uB3C5 SDK \uC778\uC2A4\uD134\uC2A4\uB85C\uB294 \uD638\uCD9C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 Functions \uD658\uACBD\uC5D0\uC11C \uC0AC\uC6A9\uD558\uC138\uC694.'
|
|
5472
|
+
);
|
|
5473
|
+
}
|
|
5474
|
+
const params = new URLSearchParams();
|
|
5475
|
+
if (options?.status) params.set("status", options.status);
|
|
5476
|
+
if (options?.startDate) params.set("start_date", options.startDate);
|
|
5477
|
+
if (options?.endDate) params.set("end_date", options.endDate);
|
|
5478
|
+
if (options?.limit !== void 0)
|
|
5479
|
+
params.set("limit", String(options.limit));
|
|
5480
|
+
if (options?.offset !== void 0)
|
|
5481
|
+
params.set("offset", String(options.offset));
|
|
5482
|
+
const qs = params.toString();
|
|
5483
|
+
return this.http.get(
|
|
5484
|
+
`/v1/apps/${appId}/payments${qs ? `?${qs}` : ""}`
|
|
5485
|
+
);
|
|
5486
|
+
}
|
|
5406
5487
|
};
|
|
5407
5488
|
|
|
5408
5489
|
// src/api/subscription.ts
|
|
@@ -6004,6 +6085,28 @@ var PushAPI = class {
|
|
|
6004
6085
|
};
|
|
6005
6086
|
return this.http.post(`/v1/apps/${appId}/push/send-to-topic`, body);
|
|
6006
6087
|
}
|
|
6088
|
+
/**
|
|
6089
|
+
* 앱의 푸시 통계(도달/오픈율/클릭율, 디바이스/메시지/토픽 수)를 조회한다.
|
|
6090
|
+
*
|
|
6091
|
+
* 서버사이드 전용 — service_role(ctx.cbAdmin, management_scopes=["push:read"]) 또는 콘솔 JWT
|
|
6092
|
+
* 인증이 필요하다. sendToMembers/sendToTopic 과 동일한 위임 가드 — cb_pk_ 단독(브라우저) SDK
|
|
6093
|
+
* 인스턴스는 차단하고, 위임 Bearer(ctx.cbAdmin) 인스턴스는 허용한다.
|
|
6094
|
+
*
|
|
6095
|
+
* @example
|
|
6096
|
+
* ```typescript
|
|
6097
|
+
* // 함수(service_role, management_scopes: ["push:read"]) 안에서
|
|
6098
|
+
* const stats = await ctx.cbAdmin.push.getStats(ctx.appId)
|
|
6099
|
+
* console.log(stats.open_rate, stats.click_rate)
|
|
6100
|
+
* ```
|
|
6101
|
+
*/
|
|
6102
|
+
async getStats(appId) {
|
|
6103
|
+
if (this.http.hasPublicKey() && !this.http.hasJWT()) {
|
|
6104
|
+
throw new Error(
|
|
6105
|
+
'cb.push.getStats() \uB294 \uCF58\uC194 JWT \uB610\uB294 service_role(ctx.cbAdmin, management_scopes: ["push:read"]) \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. Public Key(cb_pk_) \uB2E8\uB3C5 SDK \uC778\uC2A4\uD134\uC2A4\uB85C\uB294 \uD638\uCD9C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 Functions \uD658\uACBD\uC5D0\uC11C \uC0AC\uC6A9\uD558\uC138\uC694.'
|
|
6106
|
+
);
|
|
6107
|
+
}
|
|
6108
|
+
return this.http.get(`/v1/apps/${appId}/push/stats`);
|
|
6109
|
+
}
|
|
6007
6110
|
// ============ Helper Methods ============
|
|
6008
6111
|
/**
|
|
6009
6112
|
* 브라우저 고유 ID 생성 (localStorage에 저장)
|
|
@@ -6064,6 +6167,72 @@ var PushAPI = class {
|
|
|
6064
6167
|
}
|
|
6065
6168
|
};
|
|
6066
6169
|
|
|
6170
|
+
// src/api/roles.ts
|
|
6171
|
+
var RolesAPI = class {
|
|
6172
|
+
constructor(http) {
|
|
6173
|
+
this.http = http;
|
|
6174
|
+
}
|
|
6175
|
+
ensureServerAuth(method) {
|
|
6176
|
+
if (this.http.hasPublicKey() && !this.http.hasJWT()) {
|
|
6177
|
+
throw new Error(
|
|
6178
|
+
`cb.roles.${method}() \uB294 \uCF58\uC194 JWT \uB610\uB294 service_role(ctx.cbAdmin, management_scopes: ["role:read" | "role:manage"]) \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. Public Key(cb_pk_) \uB2E8\uB3C5 SDK \uC778\uC2A4\uD134\uC2A4\uB85C\uB294 \uD638\uCD9C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 Functions \uD658\uACBD\uC5D0\uC11C \uC0AC\uC6A9\uD558\uC138\uC694.`
|
|
6179
|
+
);
|
|
6180
|
+
}
|
|
6181
|
+
}
|
|
6182
|
+
/** 앱의 역할 목록을 조회한다. (management_scope: `role:read`) */
|
|
6183
|
+
async list(appId) {
|
|
6184
|
+
this.ensureServerAuth("list");
|
|
6185
|
+
return this.http.get(`/v1/apps/${appId}/app-roles`);
|
|
6186
|
+
}
|
|
6187
|
+
/** 역할 상세(권한/할당 사용자 포함)를 조회한다. (management_scope: `role:read`) */
|
|
6188
|
+
async get(appId, roleId) {
|
|
6189
|
+
this.ensureServerAuth("get");
|
|
6190
|
+
return this.http.get(`/v1/apps/${appId}/app-roles/${roleId}`);
|
|
6191
|
+
}
|
|
6192
|
+
/** 역할을 생성한다. (management_scope: `role:manage`) */
|
|
6193
|
+
async create(appId, payload) {
|
|
6194
|
+
this.ensureServerAuth("create");
|
|
6195
|
+
return this.http.post(`/v1/apps/${appId}/app-roles`, {
|
|
6196
|
+
role_title: payload.title,
|
|
6197
|
+
role_description: payload.description,
|
|
6198
|
+
selected_permission_ids: payload.permissionIds ?? []
|
|
6199
|
+
});
|
|
6200
|
+
}
|
|
6201
|
+
/**
|
|
6202
|
+
* 역할을 수정한다 — **전체 동기화(replace)**. permissionIds / userIds 는 전달값으로 대체된다.
|
|
6203
|
+
* (management_scope: `role:manage`)
|
|
6204
|
+
*/
|
|
6205
|
+
async update(appId, roleId, payload) {
|
|
6206
|
+
this.ensureServerAuth("update");
|
|
6207
|
+
await this.http.put(`/v1/apps/${appId}/app-roles/${roleId}`, {
|
|
6208
|
+
role_title: payload.title,
|
|
6209
|
+
role_description: payload.description,
|
|
6210
|
+
selected_permission_ids: payload.permissionIds,
|
|
6211
|
+
selected_user_ids: payload.userIds
|
|
6212
|
+
});
|
|
6213
|
+
}
|
|
6214
|
+
/**
|
|
6215
|
+
* 역할에 사용자를 할당한다 (제목/설명/권한 보존). EditRole 이 전체 동기화라, 현재 상세를 읽어
|
|
6216
|
+
* 나머지 필드를 유지한 채 사용자 목록만 교체해 PUT 한다. userIds 는 "이 역할을 가질 사용자
|
|
6217
|
+
* 전체"다 (추가가 아니라 동기화). (management_scope: `role:manage`)
|
|
6218
|
+
*/
|
|
6219
|
+
async assign(appId, roleId, userIds) {
|
|
6220
|
+
this.ensureServerAuth("assign");
|
|
6221
|
+
const detail = await this.http.get(`/v1/apps/${appId}/app-roles/${roleId}`);
|
|
6222
|
+
await this.http.put(`/v1/apps/${appId}/app-roles/${roleId}`, {
|
|
6223
|
+
role_title: detail.role_name,
|
|
6224
|
+
role_description: detail.role_description,
|
|
6225
|
+
selected_permission_ids: detail.permission_item.map((p) => p.id),
|
|
6226
|
+
selected_user_ids: userIds
|
|
6227
|
+
});
|
|
6228
|
+
}
|
|
6229
|
+
/** 역할을 삭제한다. (management_scope: `role:manage`) */
|
|
6230
|
+
async delete(appId, roleId) {
|
|
6231
|
+
this.ensureServerAuth("delete");
|
|
6232
|
+
await this.http.delete(`/v1/apps/${appId}/app-roles/${roleId}`);
|
|
6233
|
+
}
|
|
6234
|
+
};
|
|
6235
|
+
|
|
6067
6236
|
// src/api/video.ts
|
|
6068
6237
|
var DEFAULT_CHUNK_SIZE = 5 * 1024 * 1024;
|
|
6069
6238
|
var VideoProcessingError = class extends Error {
|
|
@@ -11152,6 +11321,7 @@ var ConnectBase = class {
|
|
|
11152
11321
|
this.payment = new PaymentAPI(this.http);
|
|
11153
11322
|
this.subscription = new SubscriptionAPI(this.http);
|
|
11154
11323
|
this.push = new PushAPI(this.http);
|
|
11324
|
+
this.roles = new RolesAPI(this.http);
|
|
11155
11325
|
this.video = new VideoAPI(this.http, config.videoUrl || env("CB_VIDEO_URL") || DEFAULT_VIDEO_URL);
|
|
11156
11326
|
this.game = new GameAPI(this.http, config.gameUrl || env("CB_GAME_URL") || DEFAULT_GAME_URL, config.appId);
|
|
11157
11327
|
this.ads = new AdsAPI(this.http);
|
|
@@ -11166,7 +11336,7 @@ var ConnectBase = class {
|
|
|
11166
11336
|
const shouldAutoRestore = config.autoRestoreSession ?? true;
|
|
11167
11337
|
if (shouldAutoRestore && typeof window !== "undefined") {
|
|
11168
11338
|
if (this.isOAuthRedirectCallbackUrl()) {
|
|
11169
|
-
this.http.setBootRestorePromise(this.oauth.consumeRedirectCallbackOnBoot());
|
|
11339
|
+
this.http.setBootRestorePromise(this.oauth.consumeRedirectCallbackOnBoot(), { alwaysAwait: true });
|
|
11170
11340
|
} else if (!this.isOAuthCallbackUrl()) {
|
|
11171
11341
|
this.http.setBootRestorePromise(this.http.tryRestoreSessionFromCookie());
|
|
11172
11342
|
}
|
|
@@ -11246,6 +11416,7 @@ export {
|
|
|
11246
11416
|
GameRoom,
|
|
11247
11417
|
GameRoomTransport,
|
|
11248
11418
|
NativeAPI,
|
|
11419
|
+
RolesAPI,
|
|
11249
11420
|
SessionManager,
|
|
11250
11421
|
VideoProcessingError,
|
|
11251
11422
|
index_default as default,
|