connectbase-client 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -361,18 +361,6 @@ var HttpClient = class {
361
361
 
362
362
  // src/api/auth.ts
363
363
  var GUEST_MEMBER_TOKEN_KEY_PREFIX = "cb_guest_";
364
- function notifyVisitorTracker(memberId) {
365
- if (typeof window === "undefined") return;
366
- if (memberId) {
367
- if (typeof window.__cbSetMember === "function") {
368
- window.__cbSetMember(memberId);
369
- }
370
- } else {
371
- if (typeof window.__cbClearMember === "function") {
372
- window.__cbClearMember();
373
- }
374
- }
375
- }
376
364
  function credentialToStorageKeyHash(credential) {
377
365
  let hash = 0;
378
366
  for (let i = 0; i < credential.length; i++) {
@@ -387,6 +375,30 @@ var AuthAPI = class {
387
375
  this.http = http;
388
376
  this.guestMemberLoginPromise = null;
389
377
  this.cachedGuestMemberTokenKey = null;
378
+ this.analytics = null;
379
+ }
380
+ /**
381
+ * AnalyticsAPI 주입 — 로그인/가입/로그아웃 시 방문자 트래커에 member_id 를 전달하여
382
+ * 게스트 방문자를 회원과 연결한다. ConnectBase 컨스트럭터에서 내부적으로 호출된다.
383
+ */
384
+ _attachAnalytics(analytics) {
385
+ this.analytics = analytics;
386
+ }
387
+ notifyVisitorTracker(memberId) {
388
+ if (this.analytics) {
389
+ this.analytics.setMemberId(memberId);
390
+ return;
391
+ }
392
+ if (typeof window === "undefined") return;
393
+ if (memberId) {
394
+ if (typeof window.__cbSetMember === "function") {
395
+ window.__cbSetMember(memberId);
396
+ }
397
+ } else {
398
+ if (typeof window.__cbClearMember === "function") {
399
+ window.__cbClearMember();
400
+ }
401
+ }
390
402
  }
391
403
  /**
392
404
  * 앱의 인증 설정 조회
@@ -431,7 +443,7 @@ var AuthAPI = class {
431
443
  { skipAuth: true }
432
444
  );
433
445
  this.http.setTokens(response.access_token, response.refresh_token);
434
- notifyVisitorTracker(response.member_id);
446
+ this.notifyVisitorTracker(response.member_id);
435
447
  return response;
436
448
  }
437
449
  /**
@@ -454,7 +466,7 @@ var AuthAPI = class {
454
466
  { skipAuth: true }
455
467
  );
456
468
  this.http.setTokens(response.access_token, response.refresh_token);
457
- notifyVisitorTracker(response.member_id);
469
+ this.notifyVisitorTracker(response.member_id);
458
470
  return response;
459
471
  }
460
472
  /**
@@ -525,7 +537,7 @@ var AuthAPI = class {
525
537
  await this.http.post("/v1/auth/logout");
526
538
  } finally {
527
539
  this.http.clearTokens();
528
- notifyVisitorTracker(null);
540
+ this.notifyVisitorTracker(null);
529
541
  }
530
542
  }
531
543
  /**
@@ -547,7 +559,7 @@ var AuthAPI = class {
547
559
  "/v1/public/app-members/me"
548
560
  );
549
561
  if (memberInfo.is_active) {
550
- notifyVisitorTracker(memberInfo.member_id);
562
+ this.notifyVisitorTracker(memberInfo.member_id);
551
563
  return {
552
564
  member_id: memberInfo.member_id,
553
565
  access_token: storedData.accessToken,
@@ -568,7 +580,7 @@ var AuthAPI = class {
568
580
  );
569
581
  this.http.setTokens(refreshed.access_token, refreshed.refresh_token);
570
582
  this.storeGuestMemberTokens(refreshed.access_token, refreshed.refresh_token, storedData.memberId);
571
- notifyVisitorTracker(storedData.memberId);
583
+ this.notifyVisitorTracker(storedData.memberId);
572
584
  return {
573
585
  member_id: storedData.memberId,
574
586
  access_token: refreshed.access_token,
@@ -588,7 +600,7 @@ var AuthAPI = class {
588
600
  );
589
601
  this.http.setTokens(response.access_token, response.refresh_token);
590
602
  this.storeGuestMemberTokens(response.access_token, response.refresh_token, response.member_id);
591
- notifyVisitorTracker(response.member_id);
603
+ this.notifyVisitorTracker(response.member_id);
592
604
  return response;
593
605
  }
594
606
  isTokenExpired(token) {
@@ -1051,7 +1063,7 @@ var DatabaseAPI = class {
1051
1063
  */
1052
1064
  async listSecurityRules(appId) {
1053
1065
  const response = await this.http.get(
1054
- `/v1/apps/${appId}/security/rules`
1066
+ `/v1/apps/${appId}/databases/security/rules`
1055
1067
  );
1056
1068
  return response.rules;
1057
1069
  }
@@ -1060,7 +1072,7 @@ var DatabaseAPI = class {
1060
1072
  */
1061
1073
  async createSecurityRule(appId, data) {
1062
1074
  return this.http.post(
1063
- `/v1/apps/${appId}/security/rules`,
1075
+ `/v1/apps/${appId}/databases/security/rules`,
1064
1076
  data
1065
1077
  );
1066
1078
  }
@@ -1069,7 +1081,7 @@ var DatabaseAPI = class {
1069
1081
  */
1070
1082
  async updateSecurityRule(appId, ruleId, data) {
1071
1083
  return this.http.put(
1072
- `/v1/apps/${appId}/security/rules/${ruleId}`,
1084
+ `/v1/apps/${appId}/databases/security/rules/${ruleId}`,
1073
1085
  data
1074
1086
  );
1075
1087
  }
@@ -1077,7 +1089,7 @@ var DatabaseAPI = class {
1077
1089
  * 보안 규칙 삭제
1078
1090
  */
1079
1091
  async deleteSecurityRule(appId, ruleId) {
1080
- await this.http.delete(`/v1/apps/${appId}/security/rules/${ruleId}`);
1092
+ await this.http.delete(`/v1/apps/${appId}/databases/security/rules/${ruleId}`);
1081
1093
  }
1082
1094
  // ============ Indexes ============
1083
1095
  /**
@@ -1085,7 +1097,7 @@ var DatabaseAPI = class {
1085
1097
  */
1086
1098
  async listIndexes(appId, tableId) {
1087
1099
  const response = await this.http.get(
1088
- `/v1/apps/${appId}/tables/${tableId}/indexes`
1100
+ `/v1/apps/${appId}/databases/tables/${tableId}/indexes`
1089
1101
  );
1090
1102
  return response.indexes;
1091
1103
  }
@@ -1094,7 +1106,7 @@ var DatabaseAPI = class {
1094
1106
  */
1095
1107
  async createIndex(appId, tableId, data) {
1096
1108
  return this.http.post(
1097
- `/v1/apps/${appId}/tables/${tableId}/indexes`,
1109
+ `/v1/apps/${appId}/databases/tables/${tableId}/indexes`,
1098
1110
  data
1099
1111
  );
1100
1112
  }
@@ -1102,72 +1114,79 @@ var DatabaseAPI = class {
1102
1114
  * 인덱스 삭제
1103
1115
  */
1104
1116
  async deleteIndex(appId, tableId, indexId) {
1105
- await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/indexes/${indexId}`);
1117
+ await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/indexes/${indexId}`);
1106
1118
  }
1107
1119
  /**
1108
1120
  * 인덱스 분석 및 추천
1109
1121
  */
1110
1122
  async analyzeIndexes(appId, tableId) {
1111
1123
  return this.http.get(
1112
- `/v1/apps/${appId}/tables/${tableId}/indexes/analyze`
1124
+ `/v1/apps/${appId}/databases/tables/${tableId}/indexes/analyze`
1113
1125
  );
1114
1126
  }
1115
1127
  // ============ Search Indexes ============
1116
1128
  async listSearchIndexes(appId, tableId) {
1117
1129
  const response = await this.http.get(
1118
- `/v1/apps/${appId}/tables/${tableId}/search-indexes`
1130
+ `/v1/apps/${appId}/databases/tables/${tableId}/search-indexes`
1119
1131
  );
1120
1132
  return response.indexes;
1121
1133
  }
1122
1134
  async createSearchIndex(appId, tableId, data) {
1123
1135
  return this.http.post(
1124
- `/v1/apps/${appId}/tables/${tableId}/search-indexes`,
1136
+ `/v1/apps/${appId}/databases/tables/${tableId}/search-indexes`,
1125
1137
  data
1126
1138
  );
1127
1139
  }
1128
1140
  async deleteSearchIndex(appId, tableId, indexId) {
1129
- await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/search-indexes/${indexId}`);
1141
+ await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/search-indexes/${indexId}`);
1130
1142
  }
1131
1143
  // ============ Geo Indexes ============
1132
1144
  async listGeoIndexes(appId, tableId) {
1133
1145
  const response = await this.http.get(
1134
- `/v1/apps/${appId}/tables/${tableId}/geo-indexes`
1146
+ `/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes`
1135
1147
  );
1136
1148
  return response.indexes;
1137
1149
  }
1138
1150
  async createGeoIndex(appId, tableId, data) {
1139
1151
  return this.http.post(
1140
- `/v1/apps/${appId}/tables/${tableId}/geo-indexes`,
1152
+ `/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes`,
1141
1153
  data
1142
1154
  );
1143
1155
  }
1144
1156
  async deleteGeoIndex(appId, tableId, indexId) {
1145
- await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/geo-indexes/${indexId}`);
1157
+ await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes/${indexId}`);
1146
1158
  }
1147
1159
  // ============ Relations ============
1148
1160
  /**
1149
- * 테이블 릴레이션 목록 조회
1161
+ * 테이블 릴레이션 목록 조회. `sourceTable` 생략 시 앱 전체의 릴레이션을 반환.
1162
+ *
1163
+ * 서버 경로: `GET /v1/apps/:appID/databases/relations[?source_table=...]`
1150
1164
  */
1151
- async listRelations(appId, tableId) {
1165
+ async listRelations(appId, sourceTable) {
1166
+ const qs = sourceTable ? `?source_table=${encodeURIComponent(sourceTable)}` : "";
1152
1167
  const response = await this.http.get(
1153
- `/v1/apps/${appId}/tables/${tableId}/relations`
1168
+ `/v1/apps/${appId}/databases/relations${qs}`
1154
1169
  );
1155
1170
  return response.relations;
1156
1171
  }
1157
1172
  /**
1158
- * 릴레이션 생성
1173
+ * 릴레이션 생성.
1174
+ *
1175
+ * 서버 경로: `POST /v1/apps/:appID/databases/relations` — body 내 `source_table`/`target_table` 로 테이블 지정.
1159
1176
  */
1160
- async createRelation(appId, tableId, data) {
1177
+ async createRelation(appId, data) {
1161
1178
  return this.http.post(
1162
- `/v1/apps/${appId}/tables/${tableId}/relations`,
1179
+ `/v1/apps/${appId}/databases/relations`,
1163
1180
  data
1164
1181
  );
1165
1182
  }
1166
1183
  /**
1167
- * 릴레이션 삭제
1184
+ * 릴레이션 삭제. `relationId` 는 서버에서 발급한 UUID (listRelations 로 조회해 얻음).
1185
+ *
1186
+ * 서버 경로: `DELETE /v1/apps/:appID/databases/relations/:relationID`
1168
1187
  */
1169
- async deleteRelation(appId, tableId, relationName) {
1170
- await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/relations/${relationName}`);
1188
+ async deleteRelation(appId, relationId) {
1189
+ await this.http.delete(`/v1/apps/${appId}/databases/relations/${relationId}`);
1171
1190
  }
1172
1191
  // ============ Triggers ============
1173
1192
  /**
@@ -1175,7 +1194,7 @@ var DatabaseAPI = class {
1175
1194
  */
1176
1195
  async listTriggers(appId) {
1177
1196
  const response = await this.http.get(
1178
- `/v1/apps/${appId}/triggers`
1197
+ `/v1/apps/${appId}/databases/triggers`
1179
1198
  );
1180
1199
  return response.triggers;
1181
1200
  }
@@ -1184,7 +1203,7 @@ var DatabaseAPI = class {
1184
1203
  */
1185
1204
  async createTrigger(appId, data) {
1186
1205
  return this.http.post(
1187
- `/v1/apps/${appId}/triggers`,
1206
+ `/v1/apps/${appId}/databases/triggers`,
1188
1207
  data
1189
1208
  );
1190
1209
  }
@@ -1193,7 +1212,7 @@ var DatabaseAPI = class {
1193
1212
  */
1194
1213
  async updateTrigger(appId, triggerId, data) {
1195
1214
  return this.http.put(
1196
- `/v1/apps/${appId}/triggers/${triggerId}`,
1215
+ `/v1/apps/${appId}/databases/triggers/${triggerId}`,
1197
1216
  data
1198
1217
  );
1199
1218
  }
@@ -1201,7 +1220,7 @@ var DatabaseAPI = class {
1201
1220
  * 트리거 삭제
1202
1221
  */
1203
1222
  async deleteTrigger(appId, triggerId) {
1204
- await this.http.delete(`/v1/apps/${appId}/triggers/${triggerId}`);
1223
+ await this.http.delete(`/v1/apps/${appId}/databases/triggers/${triggerId}`);
1205
1224
  }
1206
1225
  // ============ Lifecycle ============
1207
1226
  /**
@@ -7786,6 +7805,7 @@ function parseUTM() {
7786
7805
  var AnalyticsAPI = class {
7787
7806
  constructor(http) {
7788
7807
  this.storageWebId = null;
7808
+ this.memberId = null;
7789
7809
  this.eventQueue = [];
7790
7810
  this.batchTimer = null;
7791
7811
  this.isInitialized = false;
@@ -7919,13 +7939,33 @@ var AnalyticsAPI = class {
7919
7939
  }
7920
7940
  /**
7921
7941
  * 사용자 식별 (로그인 시)
7942
+ * 이후 모든 방문 배치에 `app_member_id`가 첨부되어 게스트 방문자가 회원으로 연결됩니다.
7922
7943
  */
7923
7944
  identify(memberId) {
7924
- if (!this.canTrack()) return;
7925
- if (typeof window.__cbSetMember === "function") {
7926
- window.__cbSetMember(memberId);
7945
+ this.setMemberId(memberId);
7946
+ }
7947
+ /**
7948
+ * 방문자 트래커에 현재 회원 ID 설정 (로그인/게스트 가입 시 호출)
7949
+ * null 을 넘기면 익명 상태로 복귀 (로그아웃).
7950
+ */
7951
+ setMemberId(memberId) {
7952
+ this.memberId = memberId || null;
7953
+ if (typeof window !== "undefined") {
7954
+ if (memberId) {
7955
+ if (typeof window.__cbSetMember === "function") {
7956
+ window.__cbSetMember(memberId);
7957
+ }
7958
+ } else {
7959
+ if (typeof window.__cbClearMember === "function") {
7960
+ window.__cbClearMember();
7961
+ }
7962
+ }
7927
7963
  }
7928
- this.log("User identified", { memberId });
7964
+ this.log("Member id set", { memberId });
7965
+ }
7966
+ /** 현재 설정된 회원 ID 조회 (미설정 시 null) */
7967
+ getMemberId() {
7968
+ return this.memberId;
7929
7969
  }
7930
7970
  /**
7931
7971
  * 히트맵 수집 활성화 (opt-in)
@@ -8038,6 +8078,7 @@ var AnalyticsAPI = class {
8038
8078
  `${prefix}/storages/web/${this.storageWebId}/visitors/batch`,
8039
8079
  {
8040
8080
  visitor_uid: this.session.visitorUid,
8081
+ ...this.memberId ? { app_member_id: this.memberId } : {},
8041
8082
  events: events.map((e) => ({
8042
8083
  timestamp: e.timestamp,
8043
8084
  page_path: e.page_path || "",
@@ -8078,6 +8119,7 @@ var AnalyticsAPI = class {
8078
8119
  const url = `${baseUrl}${prefix}/storages/web/${this.storageWebId}/visitors/batch`;
8079
8120
  const body = JSON.stringify({
8080
8121
  visitor_uid: this.session.visitorUid,
8122
+ ...this.memberId ? { app_member_id: this.memberId } : {},
8081
8123
  events: events.map((e) => ({
8082
8124
  timestamp: e.timestamp,
8083
8125
  page_path: e.page_path || "",
@@ -8941,6 +8983,7 @@ var ConnectBase = class {
8941
8983
  this.ai = new AIAPI(this.http);
8942
8984
  this.queue = new QueueAPI(this.http);
8943
8985
  this.analytics = new AnalyticsAPI(this.http);
8986
+ this.auth._attachAnalytics(this.analytics);
8944
8987
  }
8945
8988
  /**
8946
8989
  * 수동으로 토큰 설정 (기존 토큰으로 세션 복원 시)