connectbase-client 3.35.2 → 3.36.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
@@ -5471,11 +5471,23 @@ var PaymentAPI = class {
5471
5471
  * // Mount PaymentElement, then:
5472
5472
  * // stripe.confirmPayment({ elements, redirect: 'if_required' })
5473
5473
  * }
5474
+ *
5475
+ * // PayApp 결제 플로우 (위젯 불필요 — 호스팅 결제창으로 redirect)
5476
+ * // 결제 결과는 서버의 feedbackurl webhook 으로 확정되며, 사용자는 success_url 로 복귀한다.
5477
+ * if (result.payment_provider === 'payapp' && result.payapp_pay_url) {
5478
+ * window.location.href = result.payapp_pay_url
5479
+ * }
5474
5480
  * ```
5481
+ *
5482
+ * @remarks
5483
+ * PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
5475
5484
  */
5476
5485
  async prepare(data) {
5477
5486
  const prefix = this.getPublicPrefix();
5478
- return this.http.post(`${prefix}/payments/prepare`, data);
5487
+ return this.http.post(
5488
+ `${prefix}/payments/prepare`,
5489
+ data
5490
+ );
5479
5491
  }
5480
5492
  /**
5481
5493
  * Stripe-hosted 결제 페이지 세션 생성 (client_secret 미노출 플로우).
@@ -5539,7 +5551,10 @@ var PaymentAPI = class {
5539
5551
  */
5540
5552
  async confirm(data) {
5541
5553
  const prefix = this.getPublicPrefix();
5542
- return this.http.post(`${prefix}/payments/confirm`, data);
5554
+ return this.http.post(
5555
+ `${prefix}/payments/confirm`,
5556
+ data
5557
+ );
5543
5558
  }
5544
5559
  /**
5545
5560
  * 결제 취소
@@ -6093,20 +6108,22 @@ var PushAPI = class {
6093
6108
  }
6094
6109
  // ============ Server-side Send (Functions / cb_sk_ 전용) ============
6095
6110
  /**
6096
- * 회원 ID 목록으로 푸시 발송 — Functions / cb_sk_ 인증 환경 전용.
6111
+ * 회원 ID 목록으로 푸시 발송 — Functions / 서버사이드 인증 환경 전용.
6097
6112
  *
6098
- * 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT 또는 User Secret Key
6099
- * (`cb_sk_`) 받는다. 브라우저 SDK 의 Public Key(`cb_pk_`) 인스턴스에서는 호출
6100
- * 자체가 차단되며, 권한 누설을 막기 위해 명확한 에러를 던진다.
6113
+ * 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT, User Secret Key(`cb_sk_`),
6114
+ * 또는 service_role 토큰(`ctx.cbAdmin`) 받는다. 브라우저 SDK 의 Public Key(`cb_pk_`)
6115
+ * **단독** 인스턴스에서는 호출 자체가 차단되며(권한 누설 방지), 명확한 에러를 던진다.
6116
+ * 위임 Bearer 토큰을 가진 인스턴스(`ctx.cbAdmin`/`ctx.cb`)는 cb_pk_ 가 앱 식별용으로만
6117
+ * 실리므로 허용된다.
6101
6118
  *
6102
- * @param appId 발송 대상 앱 ID (cb_sk_ 환경은 user 단위 권한이므로 명시 전달).
6119
+ * @param appId 발송 대상 앱 ID.
6103
6120
  * @param memberIds 받는 회원 ID 배열 (UUID).
6104
6121
  * @param payload 푸시 내용/옵션.
6105
6122
  *
6106
6123
  * @example
6107
6124
  * ```ts
6108
- * // ConnectBase Function (Node.js, secrets.CB_SECRET_KEY 주입)
6109
- * const result = await cb.push.sendToMembers(APP_ID, [memberId], {
6125
+ * // ConnectBase Function (service_role=true) — 시크릿 키 없이 ctx.cbAdmin 으로 발송
6126
+ * const result = await ctx.cbAdmin.push.sendToMembers(ctx.appId, [memberId], {
6110
6127
  * title: '새 알림',
6111
6128
  * body: '확인해보세요',
6112
6129
  * data: { route: '/notifications' },
@@ -6115,9 +6132,9 @@ var PushAPI = class {
6115
6132
  * ```
6116
6133
  */
6117
6134
  async sendToMembers(appId, memberIds, payload) {
6118
- if (this.http.hasPublicKey()) {
6135
+ if (this.http.hasPublicKey() && !this.http.hasJWT()) {
6119
6136
  throw new Error(
6120
- "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."
6137
+ "cb.push.sendToMembers() \uB294 User Secret Key(cb_sk_), \uCF58\uC194 JWT, \uB610\uB294 service_role(ctx.cbAdmin) \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."
6121
6138
  );
6122
6139
  }
6123
6140
  if (memberIds.length === 0) {
@@ -6569,8 +6586,9 @@ var VideoAPI = class {
6569
6586
  *
6570
6587
  * @example
6571
6588
  * ```ts
6572
- * const { url, expires_at } = await cb.video.getStreamUrl(videoId, '720p')
6573
- * videoElement.src = url
6589
+ * const { master_playlist, qualities, expires_at } = await cb.video.getStreamUrl(videoId)
6590
+ * videoElement.src = master_playlist // 적응형 비트레이트(HLS.js 등으로 재생)
6591
+ * // 특정 화질 고정이 필요하면 qualities['720p'] 사용
6574
6592
  * ```
6575
6593
  */
6576
6594
  async getStreamUrl(videoId, quality) {
@@ -6749,7 +6767,8 @@ var VideoAPI = class {
6749
6767
  */
6750
6768
  async postComment(videoId, content, parentId) {
6751
6769
  const prefix = this.getPublicPrefix();
6752
- return this.videoFetch("POST", `${prefix}/videos/${videoId}/comments`, {
6770
+ return this.videoFetch("POST", `${prefix}/comments`, {
6771
+ video_id: videoId,
6753
6772
  content,
6754
6773
  parent_id: parentId
6755
6774
  });
@@ -6816,31 +6835,31 @@ var VideoAPI = class {
6816
6835
  const prefix = this.getPublicPrefix();
6817
6836
  const response = await this.videoFetch(
6818
6837
  "GET",
6819
- `${prefix}/channels/${channelId}/memberships/tiers`
6838
+ `${prefix}/channels/${channelId}/membership/tiers`
6820
6839
  );
6821
6840
  return response.tiers;
6822
6841
  }
6823
6842
  /**
6824
6843
  * Join a membership tier
6844
+ *
6845
+ * @param _channelId 현재 서버에서 무시됩니다 (tier 가 채널을 함의). API 안정성을 위해 시그니처만 유지.
6846
+ * @param tierId 가입할 멤버십 티어 ID
6825
6847
  */
6826
- async joinMembership(channelId, tierId) {
6848
+ async joinMembership(_channelId, tierId) {
6827
6849
  const prefix = this.getPublicPrefix();
6828
- return this.videoFetch(
6829
- "POST",
6830
- `${prefix}/channels/${channelId}/memberships/${tierId}/join`,
6831
- {}
6832
- );
6850
+ return this.videoFetch("POST", `${prefix}/membership/join`, {
6851
+ tier_id: tierId
6852
+ });
6833
6853
  }
6834
6854
  /**
6835
6855
  * Cancel membership
6856
+ *
6857
+ * @param _channelId 현재 서버에서 무시됩니다. API 안정성을 위해 시그니처만 유지.
6858
+ * @param membershipId 취소할 멤버십 ID
6836
6859
  */
6837
- async cancelMembership(channelId, membershipId) {
6860
+ async cancelMembership(_channelId, membershipId) {
6838
6861
  const prefix = this.getPublicPrefix();
6839
- await this.videoFetch(
6840
- "POST",
6841
- `${prefix}/channels/${channelId}/memberships/${membershipId}/cancel`,
6842
- {}
6843
- );
6862
+ await this.videoFetch("POST", `${prefix}/membership/${membershipId}/cancel`, {});
6844
6863
  }
6845
6864
  // ========== Super Chat Operations ==========
6846
6865
  /**
@@ -6868,13 +6887,15 @@ var VideoAPI = class {
6868
6887
  // ========== Recommendation Operations ==========
6869
6888
  /**
6870
6889
  * Get recommended videos
6890
+ *
6891
+ * @deprecated Use getHomeFeed() — 동일한 개인화 피드(`/recommendations/feed`)를 반환합니다.
6871
6892
  */
6872
6893
  async getRecommendations(limit) {
6873
6894
  const prefix = this.getPublicPrefix();
6874
6895
  const params = limit ? `?limit=${limit}` : "";
6875
6896
  const response = await this.videoFetch(
6876
6897
  "GET",
6877
- `${prefix}/recommendations${params}`
6898
+ `${prefix}/recommendations/feed${params}`
6878
6899
  );
6879
6900
  return response.videos;
6880
6901
  }
@@ -6886,7 +6907,7 @@ var VideoAPI = class {
6886
6907
  const params = limit ? `?limit=${limit}` : "";
6887
6908
  const response = await this.videoFetch(
6888
6909
  "GET",
6889
- `${prefix}/recommendations/home${params}`
6910
+ `${prefix}/recommendations/feed${params}`
6890
6911
  );
6891
6912
  return response.videos;
6892
6913
  }
@@ -6898,7 +6919,7 @@ var VideoAPI = class {
6898
6919
  const params = limit ? `?limit=${limit}` : "";
6899
6920
  const response = await this.videoFetch(
6900
6921
  "GET",
6901
- `${prefix}/recommendations/related/${videoId}${params}`
6922
+ `${prefix}/videos/${videoId}/related${params}`
6902
6923
  );
6903
6924
  return response.videos;
6904
6925
  }
@@ -6919,9 +6940,17 @@ var VideoAPI = class {
6919
6940
  */
6920
6941
  async submitFeedback(videoId, feedback) {
6921
6942
  const prefix = this.getPublicPrefix();
6922
- await this.videoFetch("POST", `${prefix}/recommendations/feedback`, {
6943
+ if (feedback === "not_interested") {
6944
+ await this.videoFetch(
6945
+ "POST",
6946
+ `${prefix}/recommendations/not-interested/${videoId}`,
6947
+ {}
6948
+ );
6949
+ return;
6950
+ }
6951
+ await this.videoFetch("POST", `${prefix}/recommendations/interactions`, {
6923
6952
  video_id: videoId,
6924
- feedback
6953
+ type: "like"
6925
6954
  });
6926
6955
  }
6927
6956
  };
@@ -6963,7 +6992,7 @@ var GameConfigAPI = class {
6963
6992
  /**
6964
6993
  * 단일 기능 활성화 — set() 의 편의 wrapper.
6965
6994
  *
6966
- * @example await cb.game.config.enable(appId, "matchqueue")
6995
+ * @example await cb.game.config.enable(appId, "matchqueue_enabled")
6967
6996
  */
6968
6997
  async enable(appId, feature) {
6969
6998
  return this.set(appId, { [feature]: true });
@@ -7621,7 +7650,7 @@ var GameAPI = class {
7621
7650
  const response = await fetch(`${this.gameServerUrl}/v1/game/${id}/rooms/${roomId}/spectators`, {
7622
7651
  method: "POST",
7623
7652
  headers: { ...this.getHeaders(), "Content-Type": "application/json" },
7624
- body: JSON.stringify({ player_id: playerId })
7653
+ body: JSON.stringify({ user_id: playerId })
7625
7654
  });
7626
7655
  if (!response.ok) throw new Error(`Failed to join spectator: ${response.statusText}`);
7627
7656
  return response.json();
@@ -10947,11 +10976,11 @@ var GameRoomTransport = class {
10947
10976
  });
10948
10977
  }
10949
10978
  // Private methods
10950
- send(type, data) {
10979
+ send(type, data, msgId) {
10951
10980
  if (!this.transport?.isConnected()) {
10952
10981
  throw new GameError({ code: "NOT_CONNECTED", message: "Not connected" });
10953
10982
  }
10954
- const message = JSON.stringify({ type, data });
10983
+ const message = JSON.stringify({ type, data, msg_id: msgId });
10955
10984
  this.transport.send(message, true);
10956
10985
  }
10957
10986
  sendWithHandler(type, data, handler) {
@@ -10960,14 +10989,14 @@ var GameRoomTransport = class {
10960
10989
  setTimeout(() => {
10961
10990
  this.pendingHandlers.delete(id);
10962
10991
  }, 1e4);
10963
- this.send(type, { ...data, _msg_id: id });
10992
+ this.send(type, data, id);
10964
10993
  }
10965
10994
  handleMessage(data) {
10966
10995
  try {
10967
10996
  const msg = JSON.parse(data);
10968
- if (msg._msg_id && this.pendingHandlers.has(msg._msg_id)) {
10969
- const handler = this.pendingHandlers.get(msg._msg_id);
10970
- this.pendingHandlers.delete(msg._msg_id);
10997
+ if (msg.msg_id && this.pendingHandlers.has(msg.msg_id)) {
10998
+ const handler = this.pendingHandlers.get(msg.msg_id);
10999
+ this.pendingHandlers.delete(msg.msg_id);
10971
11000
  handler(msg);
10972
11001
  return;
10973
11002
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "connectbase-client",
3
- "version": "3.35.2",
3
+ "version": "3.36.0",
4
4
  "description": "Connect Base JavaScript/TypeScript SDK for browser and Node.js",
5
5
  "repository": {
6
6
  "type": "git",