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.mjs CHANGED
@@ -323,18 +323,6 @@ var HttpClient = class {
323
323
 
324
324
  // src/api/auth.ts
325
325
  var GUEST_MEMBER_TOKEN_KEY_PREFIX = "cb_guest_";
326
- function notifyVisitorTracker(memberId) {
327
- if (typeof window === "undefined") return;
328
- if (memberId) {
329
- if (typeof window.__cbSetMember === "function") {
330
- window.__cbSetMember(memberId);
331
- }
332
- } else {
333
- if (typeof window.__cbClearMember === "function") {
334
- window.__cbClearMember();
335
- }
336
- }
337
- }
338
326
  function credentialToStorageKeyHash(credential) {
339
327
  let hash = 0;
340
328
  for (let i = 0; i < credential.length; i++) {
@@ -349,6 +337,30 @@ var AuthAPI = class {
349
337
  this.http = http;
350
338
  this.guestMemberLoginPromise = null;
351
339
  this.cachedGuestMemberTokenKey = null;
340
+ this.analytics = null;
341
+ }
342
+ /**
343
+ * AnalyticsAPI 주입 — 로그인/가입/로그아웃 시 방문자 트래커에 member_id 를 전달하여
344
+ * 게스트 방문자를 회원과 연결한다. ConnectBase 컨스트럭터에서 내부적으로 호출된다.
345
+ */
346
+ _attachAnalytics(analytics) {
347
+ this.analytics = analytics;
348
+ }
349
+ notifyVisitorTracker(memberId) {
350
+ if (this.analytics) {
351
+ this.analytics.setMemberId(memberId);
352
+ return;
353
+ }
354
+ if (typeof window === "undefined") return;
355
+ if (memberId) {
356
+ if (typeof window.__cbSetMember === "function") {
357
+ window.__cbSetMember(memberId);
358
+ }
359
+ } else {
360
+ if (typeof window.__cbClearMember === "function") {
361
+ window.__cbClearMember();
362
+ }
363
+ }
352
364
  }
353
365
  /**
354
366
  * 앱의 인증 설정 조회
@@ -393,7 +405,7 @@ var AuthAPI = class {
393
405
  { skipAuth: true }
394
406
  );
395
407
  this.http.setTokens(response.access_token, response.refresh_token);
396
- notifyVisitorTracker(response.member_id);
408
+ this.notifyVisitorTracker(response.member_id);
397
409
  return response;
398
410
  }
399
411
  /**
@@ -416,7 +428,7 @@ var AuthAPI = class {
416
428
  { skipAuth: true }
417
429
  );
418
430
  this.http.setTokens(response.access_token, response.refresh_token);
419
- notifyVisitorTracker(response.member_id);
431
+ this.notifyVisitorTracker(response.member_id);
420
432
  return response;
421
433
  }
422
434
  /**
@@ -487,7 +499,7 @@ var AuthAPI = class {
487
499
  await this.http.post("/v1/auth/logout");
488
500
  } finally {
489
501
  this.http.clearTokens();
490
- notifyVisitorTracker(null);
502
+ this.notifyVisitorTracker(null);
491
503
  }
492
504
  }
493
505
  /**
@@ -509,7 +521,7 @@ var AuthAPI = class {
509
521
  "/v1/public/app-members/me"
510
522
  );
511
523
  if (memberInfo.is_active) {
512
- notifyVisitorTracker(memberInfo.member_id);
524
+ this.notifyVisitorTracker(memberInfo.member_id);
513
525
  return {
514
526
  member_id: memberInfo.member_id,
515
527
  access_token: storedData.accessToken,
@@ -530,7 +542,7 @@ var AuthAPI = class {
530
542
  );
531
543
  this.http.setTokens(refreshed.access_token, refreshed.refresh_token);
532
544
  this.storeGuestMemberTokens(refreshed.access_token, refreshed.refresh_token, storedData.memberId);
533
- notifyVisitorTracker(storedData.memberId);
545
+ this.notifyVisitorTracker(storedData.memberId);
534
546
  return {
535
547
  member_id: storedData.memberId,
536
548
  access_token: refreshed.access_token,
@@ -550,7 +562,7 @@ var AuthAPI = class {
550
562
  );
551
563
  this.http.setTokens(response.access_token, response.refresh_token);
552
564
  this.storeGuestMemberTokens(response.access_token, response.refresh_token, response.member_id);
553
- notifyVisitorTracker(response.member_id);
565
+ this.notifyVisitorTracker(response.member_id);
554
566
  return response;
555
567
  }
556
568
  isTokenExpired(token) {
@@ -1013,7 +1025,7 @@ var DatabaseAPI = class {
1013
1025
  */
1014
1026
  async listSecurityRules(appId) {
1015
1027
  const response = await this.http.get(
1016
- `/v1/apps/${appId}/security/rules`
1028
+ `/v1/apps/${appId}/databases/security/rules`
1017
1029
  );
1018
1030
  return response.rules;
1019
1031
  }
@@ -1022,7 +1034,7 @@ var DatabaseAPI = class {
1022
1034
  */
1023
1035
  async createSecurityRule(appId, data) {
1024
1036
  return this.http.post(
1025
- `/v1/apps/${appId}/security/rules`,
1037
+ `/v1/apps/${appId}/databases/security/rules`,
1026
1038
  data
1027
1039
  );
1028
1040
  }
@@ -1031,7 +1043,7 @@ var DatabaseAPI = class {
1031
1043
  */
1032
1044
  async updateSecurityRule(appId, ruleId, data) {
1033
1045
  return this.http.put(
1034
- `/v1/apps/${appId}/security/rules/${ruleId}`,
1046
+ `/v1/apps/${appId}/databases/security/rules/${ruleId}`,
1035
1047
  data
1036
1048
  );
1037
1049
  }
@@ -1039,7 +1051,7 @@ var DatabaseAPI = class {
1039
1051
  * 보안 규칙 삭제
1040
1052
  */
1041
1053
  async deleteSecurityRule(appId, ruleId) {
1042
- await this.http.delete(`/v1/apps/${appId}/security/rules/${ruleId}`);
1054
+ await this.http.delete(`/v1/apps/${appId}/databases/security/rules/${ruleId}`);
1043
1055
  }
1044
1056
  // ============ Indexes ============
1045
1057
  /**
@@ -1047,7 +1059,7 @@ var DatabaseAPI = class {
1047
1059
  */
1048
1060
  async listIndexes(appId, tableId) {
1049
1061
  const response = await this.http.get(
1050
- `/v1/apps/${appId}/tables/${tableId}/indexes`
1062
+ `/v1/apps/${appId}/databases/tables/${tableId}/indexes`
1051
1063
  );
1052
1064
  return response.indexes;
1053
1065
  }
@@ -1056,7 +1068,7 @@ var DatabaseAPI = class {
1056
1068
  */
1057
1069
  async createIndex(appId, tableId, data) {
1058
1070
  return this.http.post(
1059
- `/v1/apps/${appId}/tables/${tableId}/indexes`,
1071
+ `/v1/apps/${appId}/databases/tables/${tableId}/indexes`,
1060
1072
  data
1061
1073
  );
1062
1074
  }
@@ -1064,72 +1076,79 @@ var DatabaseAPI = class {
1064
1076
  * 인덱스 삭제
1065
1077
  */
1066
1078
  async deleteIndex(appId, tableId, indexId) {
1067
- await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/indexes/${indexId}`);
1079
+ await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/indexes/${indexId}`);
1068
1080
  }
1069
1081
  /**
1070
1082
  * 인덱스 분석 및 추천
1071
1083
  */
1072
1084
  async analyzeIndexes(appId, tableId) {
1073
1085
  return this.http.get(
1074
- `/v1/apps/${appId}/tables/${tableId}/indexes/analyze`
1086
+ `/v1/apps/${appId}/databases/tables/${tableId}/indexes/analyze`
1075
1087
  );
1076
1088
  }
1077
1089
  // ============ Search Indexes ============
1078
1090
  async listSearchIndexes(appId, tableId) {
1079
1091
  const response = await this.http.get(
1080
- `/v1/apps/${appId}/tables/${tableId}/search-indexes`
1092
+ `/v1/apps/${appId}/databases/tables/${tableId}/search-indexes`
1081
1093
  );
1082
1094
  return response.indexes;
1083
1095
  }
1084
1096
  async createSearchIndex(appId, tableId, data) {
1085
1097
  return this.http.post(
1086
- `/v1/apps/${appId}/tables/${tableId}/search-indexes`,
1098
+ `/v1/apps/${appId}/databases/tables/${tableId}/search-indexes`,
1087
1099
  data
1088
1100
  );
1089
1101
  }
1090
1102
  async deleteSearchIndex(appId, tableId, indexId) {
1091
- await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/search-indexes/${indexId}`);
1103
+ await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/search-indexes/${indexId}`);
1092
1104
  }
1093
1105
  // ============ Geo Indexes ============
1094
1106
  async listGeoIndexes(appId, tableId) {
1095
1107
  const response = await this.http.get(
1096
- `/v1/apps/${appId}/tables/${tableId}/geo-indexes`
1108
+ `/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes`
1097
1109
  );
1098
1110
  return response.indexes;
1099
1111
  }
1100
1112
  async createGeoIndex(appId, tableId, data) {
1101
1113
  return this.http.post(
1102
- `/v1/apps/${appId}/tables/${tableId}/geo-indexes`,
1114
+ `/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes`,
1103
1115
  data
1104
1116
  );
1105
1117
  }
1106
1118
  async deleteGeoIndex(appId, tableId, indexId) {
1107
- await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/geo-indexes/${indexId}`);
1119
+ await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes/${indexId}`);
1108
1120
  }
1109
1121
  // ============ Relations ============
1110
1122
  /**
1111
- * 테이블 릴레이션 목록 조회
1123
+ * 테이블 릴레이션 목록 조회. `sourceTable` 생략 시 앱 전체의 릴레이션을 반환.
1124
+ *
1125
+ * 서버 경로: `GET /v1/apps/:appID/databases/relations[?source_table=...]`
1112
1126
  */
1113
- async listRelations(appId, tableId) {
1127
+ async listRelations(appId, sourceTable) {
1128
+ const qs = sourceTable ? `?source_table=${encodeURIComponent(sourceTable)}` : "";
1114
1129
  const response = await this.http.get(
1115
- `/v1/apps/${appId}/tables/${tableId}/relations`
1130
+ `/v1/apps/${appId}/databases/relations${qs}`
1116
1131
  );
1117
1132
  return response.relations;
1118
1133
  }
1119
1134
  /**
1120
- * 릴레이션 생성
1135
+ * 릴레이션 생성.
1136
+ *
1137
+ * 서버 경로: `POST /v1/apps/:appID/databases/relations` — body 내 `source_table`/`target_table` 로 테이블 지정.
1121
1138
  */
1122
- async createRelation(appId, tableId, data) {
1139
+ async createRelation(appId, data) {
1123
1140
  return this.http.post(
1124
- `/v1/apps/${appId}/tables/${tableId}/relations`,
1141
+ `/v1/apps/${appId}/databases/relations`,
1125
1142
  data
1126
1143
  );
1127
1144
  }
1128
1145
  /**
1129
- * 릴레이션 삭제
1146
+ * 릴레이션 삭제. `relationId` 는 서버에서 발급한 UUID (listRelations 로 조회해 얻음).
1147
+ *
1148
+ * 서버 경로: `DELETE /v1/apps/:appID/databases/relations/:relationID`
1130
1149
  */
1131
- async deleteRelation(appId, tableId, relationName) {
1132
- await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/relations/${relationName}`);
1150
+ async deleteRelation(appId, relationId) {
1151
+ await this.http.delete(`/v1/apps/${appId}/databases/relations/${relationId}`);
1133
1152
  }
1134
1153
  // ============ Triggers ============
1135
1154
  /**
@@ -1137,7 +1156,7 @@ var DatabaseAPI = class {
1137
1156
  */
1138
1157
  async listTriggers(appId) {
1139
1158
  const response = await this.http.get(
1140
- `/v1/apps/${appId}/triggers`
1159
+ `/v1/apps/${appId}/databases/triggers`
1141
1160
  );
1142
1161
  return response.triggers;
1143
1162
  }
@@ -1146,7 +1165,7 @@ var DatabaseAPI = class {
1146
1165
  */
1147
1166
  async createTrigger(appId, data) {
1148
1167
  return this.http.post(
1149
- `/v1/apps/${appId}/triggers`,
1168
+ `/v1/apps/${appId}/databases/triggers`,
1150
1169
  data
1151
1170
  );
1152
1171
  }
@@ -1155,7 +1174,7 @@ var DatabaseAPI = class {
1155
1174
  */
1156
1175
  async updateTrigger(appId, triggerId, data) {
1157
1176
  return this.http.put(
1158
- `/v1/apps/${appId}/triggers/${triggerId}`,
1177
+ `/v1/apps/${appId}/databases/triggers/${triggerId}`,
1159
1178
  data
1160
1179
  );
1161
1180
  }
@@ -1163,7 +1182,7 @@ var DatabaseAPI = class {
1163
1182
  * 트리거 삭제
1164
1183
  */
1165
1184
  async deleteTrigger(appId, triggerId) {
1166
- await this.http.delete(`/v1/apps/${appId}/triggers/${triggerId}`);
1185
+ await this.http.delete(`/v1/apps/${appId}/databases/triggers/${triggerId}`);
1167
1186
  }
1168
1187
  // ============ Lifecycle ============
1169
1188
  /**
@@ -7748,6 +7767,7 @@ function parseUTM() {
7748
7767
  var AnalyticsAPI = class {
7749
7768
  constructor(http) {
7750
7769
  this.storageWebId = null;
7770
+ this.memberId = null;
7751
7771
  this.eventQueue = [];
7752
7772
  this.batchTimer = null;
7753
7773
  this.isInitialized = false;
@@ -7881,13 +7901,33 @@ var AnalyticsAPI = class {
7881
7901
  }
7882
7902
  /**
7883
7903
  * 사용자 식별 (로그인 시)
7904
+ * 이후 모든 방문 배치에 `app_member_id`가 첨부되어 게스트 방문자가 회원으로 연결됩니다.
7884
7905
  */
7885
7906
  identify(memberId) {
7886
- if (!this.canTrack()) return;
7887
- if (typeof window.__cbSetMember === "function") {
7888
- window.__cbSetMember(memberId);
7907
+ this.setMemberId(memberId);
7908
+ }
7909
+ /**
7910
+ * 방문자 트래커에 현재 회원 ID 설정 (로그인/게스트 가입 시 호출)
7911
+ * null 을 넘기면 익명 상태로 복귀 (로그아웃).
7912
+ */
7913
+ setMemberId(memberId) {
7914
+ this.memberId = memberId || null;
7915
+ if (typeof window !== "undefined") {
7916
+ if (memberId) {
7917
+ if (typeof window.__cbSetMember === "function") {
7918
+ window.__cbSetMember(memberId);
7919
+ }
7920
+ } else {
7921
+ if (typeof window.__cbClearMember === "function") {
7922
+ window.__cbClearMember();
7923
+ }
7924
+ }
7889
7925
  }
7890
- this.log("User identified", { memberId });
7926
+ this.log("Member id set", { memberId });
7927
+ }
7928
+ /** 현재 설정된 회원 ID 조회 (미설정 시 null) */
7929
+ getMemberId() {
7930
+ return this.memberId;
7891
7931
  }
7892
7932
  /**
7893
7933
  * 히트맵 수집 활성화 (opt-in)
@@ -8000,6 +8040,7 @@ var AnalyticsAPI = class {
8000
8040
  `${prefix}/storages/web/${this.storageWebId}/visitors/batch`,
8001
8041
  {
8002
8042
  visitor_uid: this.session.visitorUid,
8043
+ ...this.memberId ? { app_member_id: this.memberId } : {},
8003
8044
  events: events.map((e) => ({
8004
8045
  timestamp: e.timestamp,
8005
8046
  page_path: e.page_path || "",
@@ -8040,6 +8081,7 @@ var AnalyticsAPI = class {
8040
8081
  const url = `${baseUrl}${prefix}/storages/web/${this.storageWebId}/visitors/batch`;
8041
8082
  const body = JSON.stringify({
8042
8083
  visitor_uid: this.session.visitorUid,
8084
+ ...this.memberId ? { app_member_id: this.memberId } : {},
8043
8085
  events: events.map((e) => ({
8044
8086
  timestamp: e.timestamp,
8045
8087
  page_path: e.page_path || "",
@@ -8903,6 +8945,7 @@ var ConnectBase = class {
8903
8945
  this.ai = new AIAPI(this.http);
8904
8946
  this.queue = new QueueAPI(this.http);
8905
8947
  this.analytics = new AnalyticsAPI(this.http);
8948
+ this.auth._attachAnalytics(this.analytics);
8906
8949
  }
8907
8950
  /**
8908
8951
  * 수동으로 토큰 설정 (기존 토큰으로 세션 복원 시)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "connectbase-client",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "Connect Base JavaScript/TypeScript SDK for browser and Node.js",
5
5
  "repository": {
6
6
  "type": "git",