connectbase-client 1.9.1 → 1.12.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 +135 -0
- package/dist/connect-base.umd.js +3 -3
- package/dist/index.d.mts +289 -4
- package/dist/index.d.ts +289 -4
- package/dist/index.js +215 -5
- package/dist/index.mjs +215 -5
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4436,11 +4436,13 @@ var OAuthAPI = class {
|
|
|
4436
4436
|
reject(new Error(event.data.error));
|
|
4437
4437
|
return;
|
|
4438
4438
|
}
|
|
4439
|
+
const rawEmail = event.data.email;
|
|
4439
4440
|
const result = {
|
|
4440
4441
|
member_id: event.data.member_id,
|
|
4441
4442
|
access_token: event.data.access_token,
|
|
4442
4443
|
refresh_token: event.data.refresh_token,
|
|
4443
|
-
is_new_member: event.data.is_new_member === "true" || event.data.is_new_member === true
|
|
4444
|
+
is_new_member: event.data.is_new_member === "true" || event.data.is_new_member === true,
|
|
4445
|
+
...typeof rawEmail === "string" && rawEmail.length > 0 ? { email: rawEmail } : {}
|
|
4444
4446
|
};
|
|
4445
4447
|
this.http.setTokens(result.access_token, result.refresh_token);
|
|
4446
4448
|
resolve(result);
|
|
@@ -4508,11 +4510,13 @@ var OAuthAPI = class {
|
|
|
4508
4510
|
if (!accessToken || !refreshToken || !memberId) {
|
|
4509
4511
|
return null;
|
|
4510
4512
|
}
|
|
4513
|
+
const emailParam = params.get("email");
|
|
4511
4514
|
const result = {
|
|
4512
4515
|
access_token: accessToken,
|
|
4513
4516
|
refresh_token: refreshToken,
|
|
4514
4517
|
member_id: memberId,
|
|
4515
4518
|
is_new_member: params.get("is_new_member") === "true",
|
|
4519
|
+
...emailParam ? { email: emailParam } : {},
|
|
4516
4520
|
state: params.get("state") || void 0
|
|
4517
4521
|
};
|
|
4518
4522
|
if (window.opener) {
|
|
@@ -4550,6 +4554,7 @@ var OAuthAPI = class {
|
|
|
4550
4554
|
refresh_token: resp.refresh_token,
|
|
4551
4555
|
member_id: resp.member_id,
|
|
4552
4556
|
is_new_member: resp.is_new_member,
|
|
4557
|
+
...resp.email ? { email: resp.email } : {},
|
|
4553
4558
|
state: params.get("state") || void 0
|
|
4554
4559
|
};
|
|
4555
4560
|
if (window.opener) {
|
|
@@ -5226,6 +5231,53 @@ var PushAPI = class {
|
|
|
5226
5231
|
const prefix = this.getPublicPrefix();
|
|
5227
5232
|
await this.http.delete(`${prefix}/push/devices/${encodeURIComponent(deviceToken)}`);
|
|
5228
5233
|
}
|
|
5234
|
+
// ============ Server-side Send (Functions / cb_sk_ 전용) ============
|
|
5235
|
+
/**
|
|
5236
|
+
* 회원 ID 목록으로 푸시 발송 — Functions / cb_sk_ 인증 환경 전용.
|
|
5237
|
+
*
|
|
5238
|
+
* 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT 또는 User Secret Key
|
|
5239
|
+
* (`cb_sk_`) 만 받는다. 브라우저 SDK 의 Public Key(`cb_pk_`) 인스턴스에서는 호출
|
|
5240
|
+
* 자체가 차단되며, 권한 누설을 막기 위해 명확한 에러를 던진다.
|
|
5241
|
+
*
|
|
5242
|
+
* @param appId 발송 대상 앱 ID (cb_sk_ 환경은 user 단위 권한이므로 명시 전달).
|
|
5243
|
+
* @param memberIds 받는 회원 ID 배열 (UUID).
|
|
5244
|
+
* @param payload 푸시 내용/옵션.
|
|
5245
|
+
*
|
|
5246
|
+
* @example
|
|
5247
|
+
* ```ts
|
|
5248
|
+
* // ConnectBase Function (Node.js, secrets.CB_SECRET_KEY 주입)
|
|
5249
|
+
* const result = await cb.push.sendToMembers(APP_ID, [memberId], {
|
|
5250
|
+
* title: '새 알림',
|
|
5251
|
+
* body: '확인해보세요',
|
|
5252
|
+
* data: { route: '/notifications' },
|
|
5253
|
+
* })
|
|
5254
|
+
* console.log(result.message_id, result.sent_count)
|
|
5255
|
+
* ```
|
|
5256
|
+
*/
|
|
5257
|
+
async sendToMembers(appId, memberIds, payload) {
|
|
5258
|
+
if (this.http.hasPublicKey()) {
|
|
5259
|
+
throw new Error(
|
|
5260
|
+
"cb.push.sendToMembers() \uB294 User Secret Key(cb_sk_) \uB610\uB294 \uCF58\uC194 JWT \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. Public Key(cb_pk_) 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."
|
|
5261
|
+
);
|
|
5262
|
+
}
|
|
5263
|
+
if (memberIds.length === 0) {
|
|
5264
|
+
throw new Error("cb.push.sendToMembers(): memberIds \uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4.");
|
|
5265
|
+
}
|
|
5266
|
+
const body = {
|
|
5267
|
+
target_type: "members",
|
|
5268
|
+
target_member_ids: memberIds,
|
|
5269
|
+
title: payload.title,
|
|
5270
|
+
body: payload.body,
|
|
5271
|
+
...payload.imageUrl !== void 0 ? { image_url: payload.imageUrl } : {},
|
|
5272
|
+
...payload.data !== void 0 ? { data: payload.data } : {},
|
|
5273
|
+
...payload.platforms !== void 0 ? { platforms: payload.platforms } : {},
|
|
5274
|
+
...payload.ttlSeconds !== void 0 ? { ttl: payload.ttlSeconds } : {},
|
|
5275
|
+
...payload.priority !== void 0 ? { priority: payload.priority } : {},
|
|
5276
|
+
...payload.clickAction !== void 0 ? { click_action: payload.clickAction } : {},
|
|
5277
|
+
...payload.scheduledAt !== void 0 ? { scheduled_at: payload.scheduledAt } : {}
|
|
5278
|
+
};
|
|
5279
|
+
return this.http.post(`/v1/apps/${appId}/push/send`, body);
|
|
5280
|
+
}
|
|
5229
5281
|
// ============ Helper Methods ============
|
|
5230
5282
|
/**
|
|
5231
5283
|
* 브라우저 고유 ID 생성 (localStorage에 저장)
|
|
@@ -8135,6 +8187,15 @@ var SessionManager = class {
|
|
|
8135
8187
|
return generateId();
|
|
8136
8188
|
}
|
|
8137
8189
|
};
|
|
8190
|
+
function buildAnalyticsQuery(options) {
|
|
8191
|
+
if (!options) return "";
|
|
8192
|
+
const params = new URLSearchParams();
|
|
8193
|
+
if (options.start_date !== void 0) params.set("start_date", String(options.start_date));
|
|
8194
|
+
if (options.end_date !== void 0) params.set("end_date", String(options.end_date));
|
|
8195
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
8196
|
+
const qs = params.toString();
|
|
8197
|
+
return qs ? `?${qs}` : "";
|
|
8198
|
+
}
|
|
8138
8199
|
function parseUTM() {
|
|
8139
8200
|
if (typeof window === "undefined") return {};
|
|
8140
8201
|
try {
|
|
@@ -8285,15 +8346,31 @@ var AnalyticsAPI = class {
|
|
|
8285
8346
|
this.enqueue(event);
|
|
8286
8347
|
}
|
|
8287
8348
|
/**
|
|
8288
|
-
* 사용자 식별 (로그인
|
|
8289
|
-
*
|
|
8349
|
+
* 사용자 식별 (로그인 직후 호출).
|
|
8350
|
+
*
|
|
8351
|
+
* 이후 모든 방문 배치에 `app_member_id` 가 첨부되어 새 활동은 회원으로 기록됩니다.
|
|
8352
|
+
* 추가로 **현재 visitor_uid 의 기존 익명 활동을 즉시 회원에게 backfill** 하기 위해
|
|
8353
|
+
* 백엔드 `link-member` 엔드포인트를 한 번 호출합니다 (1.11.0+). 호출 실패는
|
|
8354
|
+
* silent — 다음 batch 가 닿을 때 백엔드 자동 매핑이 동일하게 처리하므로 자가 복구.
|
|
8355
|
+
*
|
|
8356
|
+
* 산업 표준(GA4 User-ID, Mixpanel/PostHog `identify`) 과 동작 정합.
|
|
8357
|
+
*
|
|
8358
|
+
* @example
|
|
8359
|
+
* ```ts
|
|
8360
|
+
* // 로그인 성공 직후
|
|
8361
|
+
* await cb.auth.signIn({ email, password })
|
|
8362
|
+
* cb.analytics.identify(member.id)
|
|
8363
|
+
* ```
|
|
8290
8364
|
*/
|
|
8291
8365
|
identify(memberId) {
|
|
8292
8366
|
this.setMemberId(memberId);
|
|
8367
|
+
this.linkMemberSilent(memberId);
|
|
8293
8368
|
}
|
|
8294
8369
|
/**
|
|
8295
|
-
* 방문자 트래커에 현재 회원 ID 설정 (로그인/게스트 가입 시 호출)
|
|
8296
|
-
*
|
|
8370
|
+
* 방문자 트래커에 현재 회원 ID 설정 (로그인/게스트 가입 시 호출).
|
|
8371
|
+
*
|
|
8372
|
+
* `identify()` 와 달리 즉시 backfill 호출은 하지 않습니다 — 단순히 이후 batch 의
|
|
8373
|
+
* `app_member_id` 값만 갱신. null 을 넘기면 익명 상태로 복귀 (로그아웃).
|
|
8297
8374
|
*/
|
|
8298
8375
|
setMemberId(memberId) {
|
|
8299
8376
|
this.memberId = memberId || null;
|
|
@@ -8310,6 +8387,25 @@ var AnalyticsAPI = class {
|
|
|
8310
8387
|
}
|
|
8311
8388
|
this.log("Member id set", { memberId });
|
|
8312
8389
|
}
|
|
8390
|
+
/**
|
|
8391
|
+
* 백엔드 link-member 엔드포인트 한 번 호출 — 즉시 backfill 트리거.
|
|
8392
|
+
*
|
|
8393
|
+
* - 첫 페이지뷰가 아직 백엔드에 닿기 전이면 visitor 가 없어 404. 무시 — 다음 batch 가
|
|
8394
|
+
* 가면 백엔드 BatchRecordVisit 가 자동 LinkMember 를 호출.
|
|
8395
|
+
* - storage_web_id 가 init 안 됐거나 모든 종류의 네트워크 오류 — silent fail.
|
|
8396
|
+
*/
|
|
8397
|
+
linkMemberSilent(memberId) {
|
|
8398
|
+
if (!this.storageWebId) return;
|
|
8399
|
+
const prefix = this.http.hasPublicKey() ? "/v1/public" : "/v1";
|
|
8400
|
+
this.http.post(
|
|
8401
|
+
`${prefix}/storages/web/${this.storageWebId}/visitors/link-member`,
|
|
8402
|
+
{
|
|
8403
|
+
visitor_uid: this.session.visitorUid,
|
|
8404
|
+
app_member_id: memberId
|
|
8405
|
+
}
|
|
8406
|
+
).catch(() => {
|
|
8407
|
+
});
|
|
8408
|
+
}
|
|
8313
8409
|
/** 현재 설정된 회원 ID 조회 (미설정 시 null) */
|
|
8314
8410
|
getMemberId() {
|
|
8315
8411
|
return this.memberId;
|
|
@@ -8403,6 +8499,120 @@ var AnalyticsAPI = class {
|
|
|
8403
8499
|
async flush() {
|
|
8404
8500
|
await this.flushQueue();
|
|
8405
8501
|
}
|
|
8502
|
+
/**
|
|
8503
|
+
* 인기 페이지 조회 (콘솔 JWT 또는 User Secret Key `cb_sk_` 인증 필요).
|
|
8504
|
+
*
|
|
8505
|
+
* 브라우저 환경에서 Public Key(`cb_pk_`) 만 가진 SDK 인스턴스로는 호출이 차단된다.
|
|
8506
|
+
* Functions / 어드민 앱 등 cb_sk_ 환경에서 사용하라.
|
|
8507
|
+
*
|
|
8508
|
+
* @param storageWebId 조회할 웹스토리지 ID. 미지정 시 `init()` 에 전달된 ID 사용.
|
|
8509
|
+
* @param options 기간/limit 옵션
|
|
8510
|
+
* @example
|
|
8511
|
+
* ```ts
|
|
8512
|
+
* const { pages } = await cb.analytics.getPopularPages('019d8...', { limit: 20 })
|
|
8513
|
+
* ```
|
|
8514
|
+
*/
|
|
8515
|
+
async getPopularPages(storageWebId, options) {
|
|
8516
|
+
const id = this.requireServerSideStorageId(storageWebId, "getPopularPages");
|
|
8517
|
+
const qs = buildAnalyticsQuery(options);
|
|
8518
|
+
return this.http.get(`/v1/storages/web/${id}/popular-pages${qs}`);
|
|
8519
|
+
}
|
|
8520
|
+
/**
|
|
8521
|
+
* 페이지 전환 플로우(Sankey) 조회 — JWT/cb_sk_ 인증 필요.
|
|
8522
|
+
*/
|
|
8523
|
+
async getNavigationFlow(storageWebId, options) {
|
|
8524
|
+
const id = this.requireServerSideStorageId(storageWebId, "getNavigationFlow");
|
|
8525
|
+
const qs = buildAnalyticsQuery(options);
|
|
8526
|
+
return this.http.get(`/v1/storages/web/${id}/navigation/flow${qs}`);
|
|
8527
|
+
}
|
|
8528
|
+
/**
|
|
8529
|
+
* 방문자 목록 조회 — JWT/cb_sk_ 인증 필요.
|
|
8530
|
+
*/
|
|
8531
|
+
async getVisitors(storageWebId, options) {
|
|
8532
|
+
const id = this.requireServerSideStorageId(storageWebId, "getVisitors");
|
|
8533
|
+
const params = new URLSearchParams();
|
|
8534
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
8535
|
+
if (options?.offset !== void 0) params.set("offset", String(options.offset));
|
|
8536
|
+
if (options?.sort_by) params.set("sort_by", options.sort_by);
|
|
8537
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
8538
|
+
return this.http.get(`/v1/storages/web/${id}/visitors${qs}`);
|
|
8539
|
+
}
|
|
8540
|
+
/**
|
|
8541
|
+
* 멤버별 합산 방문자 그룹 조회 — JWT/cb_sk_ 인증 필요. (1.11+)
|
|
8542
|
+
*
|
|
8543
|
+
* `getVisitors` 와 달리 visitor row 들을 `app_member_id` 로 합쳐 단일 row 로 반환.
|
|
8544
|
+
* 같은 사람이 PC + 모바일 + 태블릿으로 접속한 경우 visitor 3개 → 그룹 1개.
|
|
8545
|
+
* 익명 visitor 는 단일 row 로 그대로 포함되어 페이지네이션이 일관됨.
|
|
8546
|
+
*
|
|
8547
|
+
* @example
|
|
8548
|
+
* ```ts
|
|
8549
|
+
* const { groups } = await cb.analytics.getVisitorGroups('019d8...', { limit: 50 })
|
|
8550
|
+
* for (const g of groups) {
|
|
8551
|
+
* if (g.app_member_id) console.log(`${g.app_member_id}: ${g.visitor_count} 디바이스`)
|
|
8552
|
+
* }
|
|
8553
|
+
* ```
|
|
8554
|
+
*/
|
|
8555
|
+
async getVisitorGroups(storageWebId, options) {
|
|
8556
|
+
const id = this.requireServerSideStorageId(storageWebId, "getVisitorGroups");
|
|
8557
|
+
const params = new URLSearchParams();
|
|
8558
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
8559
|
+
if (options?.offset !== void 0) params.set("offset", String(options.offset));
|
|
8560
|
+
if (options?.sort_by) params.set("sort_by", options.sort_by);
|
|
8561
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
8562
|
+
return this.http.get(`/v1/storages/web/${id}/visitor-groups${qs}`);
|
|
8563
|
+
}
|
|
8564
|
+
/**
|
|
8565
|
+
* 단건 멤버 합산 방문자 조회 — JWT/cb_sk_ 인증 필요. (1.11+)
|
|
8566
|
+
*
|
|
8567
|
+
* 어드민 회원 상세 페이지처럼 **한 명만 필요**할 때. 페이지네이션 풀 다운 없이
|
|
8568
|
+
* 한 번의 호출로 합산 결과 반환.
|
|
8569
|
+
*
|
|
8570
|
+
* @example
|
|
8571
|
+
* ```ts
|
|
8572
|
+
* const v = await cb.analytics.getVisitorByMember('019d8...', memberId)
|
|
8573
|
+
* console.log(`${v.visitor_count} 디바이스, 총 ${v.total_page_views} pv`)
|
|
8574
|
+
* ```
|
|
8575
|
+
*/
|
|
8576
|
+
async getVisitorByMember(storageWebId, memberId) {
|
|
8577
|
+
const id = this.requireServerSideStorageId(storageWebId, "getVisitorByMember");
|
|
8578
|
+
return this.http.get(`/v1/storages/web/${id}/members/${memberId}/visitor`);
|
|
8579
|
+
}
|
|
8580
|
+
/**
|
|
8581
|
+
* 두 visitor 를 한 사람으로 통합하는 admin 작업 — JWT/cb_sk_ 인증 필요. (1.11+)
|
|
8582
|
+
*
|
|
8583
|
+
* 외부 인증 시스템에서 두 visitor 가 동일인임을 알았을 때 사용. source 의 자식 레코드
|
|
8584
|
+
* (page_views, daily, custom_events, experiment_assignments, heatmap_events,
|
|
8585
|
+
* session_recordings) 를 target 으로 옮기고 source visitor 는 삭제됨.
|
|
8586
|
+
*
|
|
8587
|
+
* @param request 둘 중 하나 필수: `target_visitor_uid` 또는 `target_member_id`.
|
|
8588
|
+
* @example
|
|
8589
|
+
* ```ts
|
|
8590
|
+
* await cb.analytics.mergeVisitors('019d8...', {
|
|
8591
|
+
* source_visitor_uid: 'old-uid',
|
|
8592
|
+
* target_member_id: '01a...',
|
|
8593
|
+
* })
|
|
8594
|
+
* ```
|
|
8595
|
+
*/
|
|
8596
|
+
async mergeVisitors(storageWebId, request) {
|
|
8597
|
+
const id = this.requireServerSideStorageId(storageWebId, "mergeVisitors");
|
|
8598
|
+
return this.http.post(`/v1/storages/web/${id}/visitors/merge`, request);
|
|
8599
|
+
}
|
|
8600
|
+
/**
|
|
8601
|
+
* 조회 메서드 공통 가드 — Public Key 인증 SDK 인스턴스에서는 명확한 에러를 던진다.
|
|
8602
|
+
* 백엔드 라우트는 cb_pk_ 를 거부하므로 호출 자체를 막는 것이 디버깅에 유리.
|
|
8603
|
+
*/
|
|
8604
|
+
requireServerSideStorageId(storageWebId, methodName) {
|
|
8605
|
+
if (this.http.hasPublicKey()) {
|
|
8606
|
+
throw new Error(
|
|
8607
|
+
`cb.analytics.${methodName}() \uB294 \uCF58\uC194 JWT \uB610\uB294 User Secret Key(cb_sk_) \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uBE0C\uB77C\uC6B0\uC800 SDK \uC758 Public Key(cb_pk_) \uB85C\uB294 \uD638\uCD9C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 Functions \uD658\uACBD\uC5D0\uC11C \uC0AC\uC6A9\uD558\uC138\uC694.`
|
|
8608
|
+
);
|
|
8609
|
+
}
|
|
8610
|
+
const id = storageWebId ?? this.storageWebId;
|
|
8611
|
+
if (!id) {
|
|
8612
|
+
throw new Error(`cb.analytics.${methodName}() \uD638\uCD9C \uC2DC storageWebId \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (init \uB610\uB294 \uC778\uC790\uB85C \uC804\uB2EC).`);
|
|
8613
|
+
}
|
|
8614
|
+
return id;
|
|
8615
|
+
}
|
|
8406
8616
|
/**
|
|
8407
8617
|
* 세션 매니저 접근 (고급 사용자용).
|
|
8408
8618
|
*
|