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/CHANGELOG.md +19 -0
- package/dist/connect-base.umd.js +2 -2
- package/dist/index.d.mts +52 -19
- package/dist/index.d.ts +52 -19
- package/dist/index.js +69 -40
- package/dist/index.mjs +69 -40
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1324,7 +1324,8 @@ interface BulkError {
|
|
|
1324
1324
|
error: string;
|
|
1325
1325
|
}
|
|
1326
1326
|
interface DeleteWhereResponse {
|
|
1327
|
-
|
|
1327
|
+
deleted_count: number;
|
|
1328
|
+
failed_count?: number;
|
|
1328
1329
|
}
|
|
1329
1330
|
interface SecurityRule {
|
|
1330
1331
|
id: string;
|
|
@@ -4111,8 +4112,8 @@ declare class OAuthAPI {
|
|
|
4111
4112
|
} | null>;
|
|
4112
4113
|
}
|
|
4113
4114
|
|
|
4114
|
-
type PaymentProvider =
|
|
4115
|
-
type PaymentStatus =
|
|
4115
|
+
type PaymentProvider = "toss" | "stripe" | "payapp";
|
|
4116
|
+
type PaymentStatus = "pending" | "ready" | "in_progress" | "done" | "canceled" | "partial_canceled" | "aborted" | "expired" | "failed";
|
|
4116
4117
|
interface PreparePaymentRequest {
|
|
4117
4118
|
amount: number;
|
|
4118
4119
|
order_name: string;
|
|
@@ -4134,6 +4135,8 @@ interface PreparePaymentResponse {
|
|
|
4134
4135
|
fail_url: string;
|
|
4135
4136
|
stripe_client_secret?: string;
|
|
4136
4137
|
stripe_publishable_key?: string;
|
|
4138
|
+
payapp_pay_url?: string;
|
|
4139
|
+
payapp_mul_no?: string;
|
|
4137
4140
|
}
|
|
4138
4141
|
interface CreateCheckoutSessionRequest {
|
|
4139
4142
|
amount: number;
|
|
@@ -4249,7 +4252,16 @@ declare class PaymentAPI {
|
|
|
4249
4252
|
* // Mount PaymentElement, then:
|
|
4250
4253
|
* // stripe.confirmPayment({ elements, redirect: 'if_required' })
|
|
4251
4254
|
* }
|
|
4255
|
+
*
|
|
4256
|
+
* // PayApp 결제 플로우 (위젯 불필요 — 호스팅 결제창으로 redirect)
|
|
4257
|
+
* // 결제 결과는 서버의 feedbackurl webhook 으로 확정되며, 사용자는 success_url 로 복귀한다.
|
|
4258
|
+
* if (result.payment_provider === 'payapp' && result.payapp_pay_url) {
|
|
4259
|
+
* window.location.href = result.payapp_pay_url
|
|
4260
|
+
* }
|
|
4252
4261
|
* ```
|
|
4262
|
+
*
|
|
4263
|
+
* @remarks
|
|
4264
|
+
* PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
|
|
4253
4265
|
*/
|
|
4254
4266
|
prepare(data: PreparePaymentRequest): Promise<PreparePaymentResponse>;
|
|
4255
4267
|
/**
|
|
@@ -4410,8 +4422,8 @@ interface ListBillingKeysResponse {
|
|
|
4410
4422
|
type BillingCycle = 'daily' | 'weekly' | 'monthly' | 'yearly';
|
|
4411
4423
|
type SubscriptionStatus = 'active' | 'paused' | 'canceled' | 'past_due' | 'expired' | 'trial';
|
|
4412
4424
|
interface CreateSubscriptionRequest {
|
|
4413
|
-
/** 빌링키 ID */
|
|
4414
|
-
billing_key_id
|
|
4425
|
+
/** 빌링키 ID (toss/stripe 필수, payapp 미사용 — payurl 모델) */
|
|
4426
|
+
billing_key_id?: string;
|
|
4415
4427
|
/** 플랜 이름 */
|
|
4416
4428
|
plan_name: string;
|
|
4417
4429
|
/** 플랜 설명 */
|
|
@@ -4430,6 +4442,10 @@ interface CreateSubscriptionRequest {
|
|
|
4430
4442
|
customer_email?: string;
|
|
4431
4443
|
/** 고객 이름 */
|
|
4432
4444
|
customer_name?: string;
|
|
4445
|
+
/** 고객 전화번호 (payapp 정기결제 필수 — rebillRegist recvphone) */
|
|
4446
|
+
customer_phone?: string;
|
|
4447
|
+
/** payapp 정기결제 만료일 yyyy-mm-dd (미입력시 +10년) */
|
|
4448
|
+
expire_date?: string;
|
|
4433
4449
|
/** 메타데이터 */
|
|
4434
4450
|
metadata?: Record<string, unknown>;
|
|
4435
4451
|
}
|
|
@@ -4438,6 +4454,10 @@ interface SubscriptionResponse {
|
|
|
4438
4454
|
id: string;
|
|
4439
4455
|
/** 구독 ID (문자열) */
|
|
4440
4456
|
subscription_id: string;
|
|
4457
|
+
/** 결제 프로바이더 */
|
|
4458
|
+
provider?: 'toss' | 'stripe' | 'payapp';
|
|
4459
|
+
/** payapp: 카드등록+1회차 결제창 URL. 이 URL로 사용자를 redirect 시킨다 (위젯 불필요) */
|
|
4460
|
+
payapp_pay_url?: string;
|
|
4441
4461
|
/** 플랜 이름 */
|
|
4442
4462
|
plan_name: string;
|
|
4443
4463
|
/** 플랜 설명 */
|
|
@@ -5062,20 +5082,22 @@ declare class PushAPI {
|
|
|
5062
5082
|
*/
|
|
5063
5083
|
unregisterWebPush(deviceToken: string): Promise<void>;
|
|
5064
5084
|
/**
|
|
5065
|
-
* 회원 ID 목록으로 푸시 발송 — Functions /
|
|
5085
|
+
* 회원 ID 목록으로 푸시 발송 — Functions / 서버사이드 인증 환경 전용.
|
|
5066
5086
|
*
|
|
5067
|
-
* 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT
|
|
5068
|
-
* (`
|
|
5069
|
-
* 자체가
|
|
5087
|
+
* 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT, User Secret Key(`cb_sk_`),
|
|
5088
|
+
* 또는 service_role 토큰(`ctx.cbAdmin`)을 받는다. 브라우저 SDK 의 Public Key(`cb_pk_`)
|
|
5089
|
+
* **단독** 인스턴스에서는 호출 자체가 차단되며(권한 누설 방지), 명확한 에러를 던진다.
|
|
5090
|
+
* 위임 Bearer 토큰을 가진 인스턴스(`ctx.cbAdmin`/`ctx.cb`)는 cb_pk_ 가 앱 식별용으로만
|
|
5091
|
+
* 실리므로 허용된다.
|
|
5070
5092
|
*
|
|
5071
|
-
* @param appId 발송 대상 앱 ID
|
|
5093
|
+
* @param appId 발송 대상 앱 ID.
|
|
5072
5094
|
* @param memberIds 받는 회원 ID 배열 (UUID).
|
|
5073
5095
|
* @param payload 푸시 내용/옵션.
|
|
5074
5096
|
*
|
|
5075
5097
|
* @example
|
|
5076
5098
|
* ```ts
|
|
5077
|
-
* // ConnectBase Function (
|
|
5078
|
-
* const result = await
|
|
5099
|
+
* // ConnectBase Function (service_role=true) — 시크릿 키 없이 ctx.cbAdmin 으로 발송
|
|
5100
|
+
* const result = await ctx.cbAdmin.push.sendToMembers(ctx.appId, [memberId], {
|
|
5079
5101
|
* title: '새 알림',
|
|
5080
5102
|
* body: '확인해보세요',
|
|
5081
5103
|
* data: { route: '/notifications' },
|
|
@@ -5165,9 +5187,11 @@ interface UpdateVideoRequest {
|
|
|
5165
5187
|
thumbnail_url?: string;
|
|
5166
5188
|
}
|
|
5167
5189
|
interface StreamURLResponse {
|
|
5168
|
-
|
|
5190
|
+
/** 마스터 HLS 플레이리스트 URL (적응형 비트레이트) */
|
|
5191
|
+
master_playlist: string;
|
|
5192
|
+
/** 화질 키 → 화질별 플레이리스트 URL 맵 (예: { "720p": "https://..." }) */
|
|
5193
|
+
qualities: Record<string, string>;
|
|
5169
5194
|
expires_at: string;
|
|
5170
|
-
quality?: string;
|
|
5171
5195
|
}
|
|
5172
5196
|
interface InitUploadResponse {
|
|
5173
5197
|
upload_id: string;
|
|
@@ -5470,8 +5494,9 @@ declare class VideoAPI {
|
|
|
5470
5494
|
*
|
|
5471
5495
|
* @example
|
|
5472
5496
|
* ```ts
|
|
5473
|
-
* const {
|
|
5474
|
-
* videoElement.src =
|
|
5497
|
+
* const { master_playlist, qualities, expires_at } = await cb.video.getStreamUrl(videoId)
|
|
5498
|
+
* videoElement.src = master_playlist // 적응형 비트레이트(HLS.js 등으로 재생)
|
|
5499
|
+
* // 특정 화질 고정이 필요하면 qualities['720p'] 사용
|
|
5475
5500
|
* ```
|
|
5476
5501
|
*/
|
|
5477
5502
|
getStreamUrl(videoId: string, quality?: string): Promise<StreamURLResponse>;
|
|
@@ -5597,12 +5622,18 @@ declare class VideoAPI {
|
|
|
5597
5622
|
getMembershipTiers(channelId: string): Promise<MembershipTier[]>;
|
|
5598
5623
|
/**
|
|
5599
5624
|
* Join a membership tier
|
|
5625
|
+
*
|
|
5626
|
+
* @param _channelId 현재 서버에서 무시됩니다 (tier 가 채널을 함의). API 안정성을 위해 시그니처만 유지.
|
|
5627
|
+
* @param tierId 가입할 멤버십 티어 ID
|
|
5600
5628
|
*/
|
|
5601
|
-
joinMembership(
|
|
5629
|
+
joinMembership(_channelId: string, tierId: string): Promise<ChannelMembership>;
|
|
5602
5630
|
/**
|
|
5603
5631
|
* Cancel membership
|
|
5632
|
+
*
|
|
5633
|
+
* @param _channelId 현재 서버에서 무시됩니다. API 안정성을 위해 시그니처만 유지.
|
|
5634
|
+
* @param membershipId 취소할 멤버십 ID
|
|
5604
5635
|
*/
|
|
5605
|
-
cancelMembership(
|
|
5636
|
+
cancelMembership(_channelId: string, membershipId: string): Promise<void>;
|
|
5606
5637
|
/**
|
|
5607
5638
|
* Send a super chat
|
|
5608
5639
|
*/
|
|
@@ -5613,6 +5644,8 @@ declare class VideoAPI {
|
|
|
5613
5644
|
getSuperChats(videoId: string): Promise<SuperChat[]>;
|
|
5614
5645
|
/**
|
|
5615
5646
|
* Get recommended videos
|
|
5647
|
+
*
|
|
5648
|
+
* @deprecated Use getHomeFeed() — 동일한 개인화 피드(`/recommendations/feed`)를 반환합니다.
|
|
5616
5649
|
*/
|
|
5617
5650
|
getRecommendations(limit?: number): Promise<Video[]>;
|
|
5618
5651
|
/**
|
|
@@ -5742,7 +5775,7 @@ declare class GameConfigAPI {
|
|
|
5742
5775
|
/**
|
|
5743
5776
|
* 단일 기능 활성화 — set() 의 편의 wrapper.
|
|
5744
5777
|
*
|
|
5745
|
-
* @example await cb.game.config.enable(appId, "
|
|
5778
|
+
* @example await cb.game.config.enable(appId, "matchqueue_enabled")
|
|
5746
5779
|
*/
|
|
5747
5780
|
enable(appId: string, feature: keyof GameConfig): Promise<GameConfig>;
|
|
5748
5781
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1324,7 +1324,8 @@ interface BulkError {
|
|
|
1324
1324
|
error: string;
|
|
1325
1325
|
}
|
|
1326
1326
|
interface DeleteWhereResponse {
|
|
1327
|
-
|
|
1327
|
+
deleted_count: number;
|
|
1328
|
+
failed_count?: number;
|
|
1328
1329
|
}
|
|
1329
1330
|
interface SecurityRule {
|
|
1330
1331
|
id: string;
|
|
@@ -4111,8 +4112,8 @@ declare class OAuthAPI {
|
|
|
4111
4112
|
} | null>;
|
|
4112
4113
|
}
|
|
4113
4114
|
|
|
4114
|
-
type PaymentProvider =
|
|
4115
|
-
type PaymentStatus =
|
|
4115
|
+
type PaymentProvider = "toss" | "stripe" | "payapp";
|
|
4116
|
+
type PaymentStatus = "pending" | "ready" | "in_progress" | "done" | "canceled" | "partial_canceled" | "aborted" | "expired" | "failed";
|
|
4116
4117
|
interface PreparePaymentRequest {
|
|
4117
4118
|
amount: number;
|
|
4118
4119
|
order_name: string;
|
|
@@ -4134,6 +4135,8 @@ interface PreparePaymentResponse {
|
|
|
4134
4135
|
fail_url: string;
|
|
4135
4136
|
stripe_client_secret?: string;
|
|
4136
4137
|
stripe_publishable_key?: string;
|
|
4138
|
+
payapp_pay_url?: string;
|
|
4139
|
+
payapp_mul_no?: string;
|
|
4137
4140
|
}
|
|
4138
4141
|
interface CreateCheckoutSessionRequest {
|
|
4139
4142
|
amount: number;
|
|
@@ -4249,7 +4252,16 @@ declare class PaymentAPI {
|
|
|
4249
4252
|
* // Mount PaymentElement, then:
|
|
4250
4253
|
* // stripe.confirmPayment({ elements, redirect: 'if_required' })
|
|
4251
4254
|
* }
|
|
4255
|
+
*
|
|
4256
|
+
* // PayApp 결제 플로우 (위젯 불필요 — 호스팅 결제창으로 redirect)
|
|
4257
|
+
* // 결제 결과는 서버의 feedbackurl webhook 으로 확정되며, 사용자는 success_url 로 복귀한다.
|
|
4258
|
+
* if (result.payment_provider === 'payapp' && result.payapp_pay_url) {
|
|
4259
|
+
* window.location.href = result.payapp_pay_url
|
|
4260
|
+
* }
|
|
4252
4261
|
* ```
|
|
4262
|
+
*
|
|
4263
|
+
* @remarks
|
|
4264
|
+
* PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
|
|
4253
4265
|
*/
|
|
4254
4266
|
prepare(data: PreparePaymentRequest): Promise<PreparePaymentResponse>;
|
|
4255
4267
|
/**
|
|
@@ -4410,8 +4422,8 @@ interface ListBillingKeysResponse {
|
|
|
4410
4422
|
type BillingCycle = 'daily' | 'weekly' | 'monthly' | 'yearly';
|
|
4411
4423
|
type SubscriptionStatus = 'active' | 'paused' | 'canceled' | 'past_due' | 'expired' | 'trial';
|
|
4412
4424
|
interface CreateSubscriptionRequest {
|
|
4413
|
-
/** 빌링키 ID */
|
|
4414
|
-
billing_key_id
|
|
4425
|
+
/** 빌링키 ID (toss/stripe 필수, payapp 미사용 — payurl 모델) */
|
|
4426
|
+
billing_key_id?: string;
|
|
4415
4427
|
/** 플랜 이름 */
|
|
4416
4428
|
plan_name: string;
|
|
4417
4429
|
/** 플랜 설명 */
|
|
@@ -4430,6 +4442,10 @@ interface CreateSubscriptionRequest {
|
|
|
4430
4442
|
customer_email?: string;
|
|
4431
4443
|
/** 고객 이름 */
|
|
4432
4444
|
customer_name?: string;
|
|
4445
|
+
/** 고객 전화번호 (payapp 정기결제 필수 — rebillRegist recvphone) */
|
|
4446
|
+
customer_phone?: string;
|
|
4447
|
+
/** payapp 정기결제 만료일 yyyy-mm-dd (미입력시 +10년) */
|
|
4448
|
+
expire_date?: string;
|
|
4433
4449
|
/** 메타데이터 */
|
|
4434
4450
|
metadata?: Record<string, unknown>;
|
|
4435
4451
|
}
|
|
@@ -4438,6 +4454,10 @@ interface SubscriptionResponse {
|
|
|
4438
4454
|
id: string;
|
|
4439
4455
|
/** 구독 ID (문자열) */
|
|
4440
4456
|
subscription_id: string;
|
|
4457
|
+
/** 결제 프로바이더 */
|
|
4458
|
+
provider?: 'toss' | 'stripe' | 'payapp';
|
|
4459
|
+
/** payapp: 카드등록+1회차 결제창 URL. 이 URL로 사용자를 redirect 시킨다 (위젯 불필요) */
|
|
4460
|
+
payapp_pay_url?: string;
|
|
4441
4461
|
/** 플랜 이름 */
|
|
4442
4462
|
plan_name: string;
|
|
4443
4463
|
/** 플랜 설명 */
|
|
@@ -5062,20 +5082,22 @@ declare class PushAPI {
|
|
|
5062
5082
|
*/
|
|
5063
5083
|
unregisterWebPush(deviceToken: string): Promise<void>;
|
|
5064
5084
|
/**
|
|
5065
|
-
* 회원 ID 목록으로 푸시 발송 — Functions /
|
|
5085
|
+
* 회원 ID 목록으로 푸시 발송 — Functions / 서버사이드 인증 환경 전용.
|
|
5066
5086
|
*
|
|
5067
|
-
* 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT
|
|
5068
|
-
* (`
|
|
5069
|
-
* 자체가
|
|
5087
|
+
* 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT, User Secret Key(`cb_sk_`),
|
|
5088
|
+
* 또는 service_role 토큰(`ctx.cbAdmin`)을 받는다. 브라우저 SDK 의 Public Key(`cb_pk_`)
|
|
5089
|
+
* **단독** 인스턴스에서는 호출 자체가 차단되며(권한 누설 방지), 명확한 에러를 던진다.
|
|
5090
|
+
* 위임 Bearer 토큰을 가진 인스턴스(`ctx.cbAdmin`/`ctx.cb`)는 cb_pk_ 가 앱 식별용으로만
|
|
5091
|
+
* 실리므로 허용된다.
|
|
5070
5092
|
*
|
|
5071
|
-
* @param appId 발송 대상 앱 ID
|
|
5093
|
+
* @param appId 발송 대상 앱 ID.
|
|
5072
5094
|
* @param memberIds 받는 회원 ID 배열 (UUID).
|
|
5073
5095
|
* @param payload 푸시 내용/옵션.
|
|
5074
5096
|
*
|
|
5075
5097
|
* @example
|
|
5076
5098
|
* ```ts
|
|
5077
|
-
* // ConnectBase Function (
|
|
5078
|
-
* const result = await
|
|
5099
|
+
* // ConnectBase Function (service_role=true) — 시크릿 키 없이 ctx.cbAdmin 으로 발송
|
|
5100
|
+
* const result = await ctx.cbAdmin.push.sendToMembers(ctx.appId, [memberId], {
|
|
5079
5101
|
* title: '새 알림',
|
|
5080
5102
|
* body: '확인해보세요',
|
|
5081
5103
|
* data: { route: '/notifications' },
|
|
@@ -5165,9 +5187,11 @@ interface UpdateVideoRequest {
|
|
|
5165
5187
|
thumbnail_url?: string;
|
|
5166
5188
|
}
|
|
5167
5189
|
interface StreamURLResponse {
|
|
5168
|
-
|
|
5190
|
+
/** 마스터 HLS 플레이리스트 URL (적응형 비트레이트) */
|
|
5191
|
+
master_playlist: string;
|
|
5192
|
+
/** 화질 키 → 화질별 플레이리스트 URL 맵 (예: { "720p": "https://..." }) */
|
|
5193
|
+
qualities: Record<string, string>;
|
|
5169
5194
|
expires_at: string;
|
|
5170
|
-
quality?: string;
|
|
5171
5195
|
}
|
|
5172
5196
|
interface InitUploadResponse {
|
|
5173
5197
|
upload_id: string;
|
|
@@ -5470,8 +5494,9 @@ declare class VideoAPI {
|
|
|
5470
5494
|
*
|
|
5471
5495
|
* @example
|
|
5472
5496
|
* ```ts
|
|
5473
|
-
* const {
|
|
5474
|
-
* videoElement.src =
|
|
5497
|
+
* const { master_playlist, qualities, expires_at } = await cb.video.getStreamUrl(videoId)
|
|
5498
|
+
* videoElement.src = master_playlist // 적응형 비트레이트(HLS.js 등으로 재생)
|
|
5499
|
+
* // 특정 화질 고정이 필요하면 qualities['720p'] 사용
|
|
5475
5500
|
* ```
|
|
5476
5501
|
*/
|
|
5477
5502
|
getStreamUrl(videoId: string, quality?: string): Promise<StreamURLResponse>;
|
|
@@ -5597,12 +5622,18 @@ declare class VideoAPI {
|
|
|
5597
5622
|
getMembershipTiers(channelId: string): Promise<MembershipTier[]>;
|
|
5598
5623
|
/**
|
|
5599
5624
|
* Join a membership tier
|
|
5625
|
+
*
|
|
5626
|
+
* @param _channelId 현재 서버에서 무시됩니다 (tier 가 채널을 함의). API 안정성을 위해 시그니처만 유지.
|
|
5627
|
+
* @param tierId 가입할 멤버십 티어 ID
|
|
5600
5628
|
*/
|
|
5601
|
-
joinMembership(
|
|
5629
|
+
joinMembership(_channelId: string, tierId: string): Promise<ChannelMembership>;
|
|
5602
5630
|
/**
|
|
5603
5631
|
* Cancel membership
|
|
5632
|
+
*
|
|
5633
|
+
* @param _channelId 현재 서버에서 무시됩니다. API 안정성을 위해 시그니처만 유지.
|
|
5634
|
+
* @param membershipId 취소할 멤버십 ID
|
|
5604
5635
|
*/
|
|
5605
|
-
cancelMembership(
|
|
5636
|
+
cancelMembership(_channelId: string, membershipId: string): Promise<void>;
|
|
5606
5637
|
/**
|
|
5607
5638
|
* Send a super chat
|
|
5608
5639
|
*/
|
|
@@ -5613,6 +5644,8 @@ declare class VideoAPI {
|
|
|
5613
5644
|
getSuperChats(videoId: string): Promise<SuperChat[]>;
|
|
5614
5645
|
/**
|
|
5615
5646
|
* Get recommended videos
|
|
5647
|
+
*
|
|
5648
|
+
* @deprecated Use getHomeFeed() — 동일한 개인화 피드(`/recommendations/feed`)를 반환합니다.
|
|
5616
5649
|
*/
|
|
5617
5650
|
getRecommendations(limit?: number): Promise<Video[]>;
|
|
5618
5651
|
/**
|
|
@@ -5742,7 +5775,7 @@ declare class GameConfigAPI {
|
|
|
5742
5775
|
/**
|
|
5743
5776
|
* 단일 기능 활성화 — set() 의 편의 wrapper.
|
|
5744
5777
|
*
|
|
5745
|
-
* @example await cb.game.config.enable(appId, "
|
|
5778
|
+
* @example await cb.game.config.enable(appId, "matchqueue_enabled")
|
|
5746
5779
|
*/
|
|
5747
5780
|
enable(appId: string, feature: keyof GameConfig): Promise<GameConfig>;
|
|
5748
5781
|
/**
|
package/dist/index.js
CHANGED
|
@@ -5517,11 +5517,23 @@ var PaymentAPI = class {
|
|
|
5517
5517
|
* // Mount PaymentElement, then:
|
|
5518
5518
|
* // stripe.confirmPayment({ elements, redirect: 'if_required' })
|
|
5519
5519
|
* }
|
|
5520
|
+
*
|
|
5521
|
+
* // PayApp 결제 플로우 (위젯 불필요 — 호스팅 결제창으로 redirect)
|
|
5522
|
+
* // 결제 결과는 서버의 feedbackurl webhook 으로 확정되며, 사용자는 success_url 로 복귀한다.
|
|
5523
|
+
* if (result.payment_provider === 'payapp' && result.payapp_pay_url) {
|
|
5524
|
+
* window.location.href = result.payapp_pay_url
|
|
5525
|
+
* }
|
|
5520
5526
|
* ```
|
|
5527
|
+
*
|
|
5528
|
+
* @remarks
|
|
5529
|
+
* PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
|
|
5521
5530
|
*/
|
|
5522
5531
|
async prepare(data) {
|
|
5523
5532
|
const prefix = this.getPublicPrefix();
|
|
5524
|
-
return this.http.post(
|
|
5533
|
+
return this.http.post(
|
|
5534
|
+
`${prefix}/payments/prepare`,
|
|
5535
|
+
data
|
|
5536
|
+
);
|
|
5525
5537
|
}
|
|
5526
5538
|
/**
|
|
5527
5539
|
* Stripe-hosted 결제 페이지 세션 생성 (client_secret 미노출 플로우).
|
|
@@ -5585,7 +5597,10 @@ var PaymentAPI = class {
|
|
|
5585
5597
|
*/
|
|
5586
5598
|
async confirm(data) {
|
|
5587
5599
|
const prefix = this.getPublicPrefix();
|
|
5588
|
-
return this.http.post(
|
|
5600
|
+
return this.http.post(
|
|
5601
|
+
`${prefix}/payments/confirm`,
|
|
5602
|
+
data
|
|
5603
|
+
);
|
|
5589
5604
|
}
|
|
5590
5605
|
/**
|
|
5591
5606
|
* 결제 취소
|
|
@@ -6139,20 +6154,22 @@ var PushAPI = class {
|
|
|
6139
6154
|
}
|
|
6140
6155
|
// ============ Server-side Send (Functions / cb_sk_ 전용) ============
|
|
6141
6156
|
/**
|
|
6142
|
-
* 회원 ID 목록으로 푸시 발송 — Functions /
|
|
6157
|
+
* 회원 ID 목록으로 푸시 발송 — Functions / 서버사이드 인증 환경 전용.
|
|
6143
6158
|
*
|
|
6144
|
-
* 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT
|
|
6145
|
-
* (`
|
|
6146
|
-
* 자체가
|
|
6159
|
+
* 백엔드 라우트 `POST /v1/apps/:appID/push/send` 는 콘솔 JWT, User Secret Key(`cb_sk_`),
|
|
6160
|
+
* 또는 service_role 토큰(`ctx.cbAdmin`)을 받는다. 브라우저 SDK 의 Public Key(`cb_pk_`)
|
|
6161
|
+
* **단독** 인스턴스에서는 호출 자체가 차단되며(권한 누설 방지), 명확한 에러를 던진다.
|
|
6162
|
+
* 위임 Bearer 토큰을 가진 인스턴스(`ctx.cbAdmin`/`ctx.cb`)는 cb_pk_ 가 앱 식별용으로만
|
|
6163
|
+
* 실리므로 허용된다.
|
|
6147
6164
|
*
|
|
6148
|
-
* @param appId 발송 대상 앱 ID
|
|
6165
|
+
* @param appId 발송 대상 앱 ID.
|
|
6149
6166
|
* @param memberIds 받는 회원 ID 배열 (UUID).
|
|
6150
6167
|
* @param payload 푸시 내용/옵션.
|
|
6151
6168
|
*
|
|
6152
6169
|
* @example
|
|
6153
6170
|
* ```ts
|
|
6154
|
-
* // ConnectBase Function (
|
|
6155
|
-
* const result = await
|
|
6171
|
+
* // ConnectBase Function (service_role=true) — 시크릿 키 없이 ctx.cbAdmin 으로 발송
|
|
6172
|
+
* const result = await ctx.cbAdmin.push.sendToMembers(ctx.appId, [memberId], {
|
|
6156
6173
|
* title: '새 알림',
|
|
6157
6174
|
* body: '확인해보세요',
|
|
6158
6175
|
* data: { route: '/notifications' },
|
|
@@ -6161,9 +6178,9 @@ var PushAPI = class {
|
|
|
6161
6178
|
* ```
|
|
6162
6179
|
*/
|
|
6163
6180
|
async sendToMembers(appId, memberIds, payload) {
|
|
6164
|
-
if (this.http.hasPublicKey()) {
|
|
6181
|
+
if (this.http.hasPublicKey() && !this.http.hasJWT()) {
|
|
6165
6182
|
throw new Error(
|
|
6166
|
-
"cb.push.sendToMembers() \uB294 User Secret Key(cb_sk_) \
|
|
6183
|
+
"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."
|
|
6167
6184
|
);
|
|
6168
6185
|
}
|
|
6169
6186
|
if (memberIds.length === 0) {
|
|
@@ -6615,8 +6632,9 @@ var VideoAPI = class {
|
|
|
6615
6632
|
*
|
|
6616
6633
|
* @example
|
|
6617
6634
|
* ```ts
|
|
6618
|
-
* const {
|
|
6619
|
-
* videoElement.src =
|
|
6635
|
+
* const { master_playlist, qualities, expires_at } = await cb.video.getStreamUrl(videoId)
|
|
6636
|
+
* videoElement.src = master_playlist // 적응형 비트레이트(HLS.js 등으로 재생)
|
|
6637
|
+
* // 특정 화질 고정이 필요하면 qualities['720p'] 사용
|
|
6620
6638
|
* ```
|
|
6621
6639
|
*/
|
|
6622
6640
|
async getStreamUrl(videoId, quality) {
|
|
@@ -6795,7 +6813,8 @@ var VideoAPI = class {
|
|
|
6795
6813
|
*/
|
|
6796
6814
|
async postComment(videoId, content, parentId) {
|
|
6797
6815
|
const prefix = this.getPublicPrefix();
|
|
6798
|
-
return this.videoFetch("POST", `${prefix}/
|
|
6816
|
+
return this.videoFetch("POST", `${prefix}/comments`, {
|
|
6817
|
+
video_id: videoId,
|
|
6799
6818
|
content,
|
|
6800
6819
|
parent_id: parentId
|
|
6801
6820
|
});
|
|
@@ -6862,31 +6881,31 @@ var VideoAPI = class {
|
|
|
6862
6881
|
const prefix = this.getPublicPrefix();
|
|
6863
6882
|
const response = await this.videoFetch(
|
|
6864
6883
|
"GET",
|
|
6865
|
-
`${prefix}/channels/${channelId}/
|
|
6884
|
+
`${prefix}/channels/${channelId}/membership/tiers`
|
|
6866
6885
|
);
|
|
6867
6886
|
return response.tiers;
|
|
6868
6887
|
}
|
|
6869
6888
|
/**
|
|
6870
6889
|
* Join a membership tier
|
|
6890
|
+
*
|
|
6891
|
+
* @param _channelId 현재 서버에서 무시됩니다 (tier 가 채널을 함의). API 안정성을 위해 시그니처만 유지.
|
|
6892
|
+
* @param tierId 가입할 멤버십 티어 ID
|
|
6871
6893
|
*/
|
|
6872
|
-
async joinMembership(
|
|
6894
|
+
async joinMembership(_channelId, tierId) {
|
|
6873
6895
|
const prefix = this.getPublicPrefix();
|
|
6874
|
-
return this.videoFetch(
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
{}
|
|
6878
|
-
);
|
|
6896
|
+
return this.videoFetch("POST", `${prefix}/membership/join`, {
|
|
6897
|
+
tier_id: tierId
|
|
6898
|
+
});
|
|
6879
6899
|
}
|
|
6880
6900
|
/**
|
|
6881
6901
|
* Cancel membership
|
|
6902
|
+
*
|
|
6903
|
+
* @param _channelId 현재 서버에서 무시됩니다. API 안정성을 위해 시그니처만 유지.
|
|
6904
|
+
* @param membershipId 취소할 멤버십 ID
|
|
6882
6905
|
*/
|
|
6883
|
-
async cancelMembership(
|
|
6906
|
+
async cancelMembership(_channelId, membershipId) {
|
|
6884
6907
|
const prefix = this.getPublicPrefix();
|
|
6885
|
-
await this.videoFetch(
|
|
6886
|
-
"POST",
|
|
6887
|
-
`${prefix}/channels/${channelId}/memberships/${membershipId}/cancel`,
|
|
6888
|
-
{}
|
|
6889
|
-
);
|
|
6908
|
+
await this.videoFetch("POST", `${prefix}/membership/${membershipId}/cancel`, {});
|
|
6890
6909
|
}
|
|
6891
6910
|
// ========== Super Chat Operations ==========
|
|
6892
6911
|
/**
|
|
@@ -6914,13 +6933,15 @@ var VideoAPI = class {
|
|
|
6914
6933
|
// ========== Recommendation Operations ==========
|
|
6915
6934
|
/**
|
|
6916
6935
|
* Get recommended videos
|
|
6936
|
+
*
|
|
6937
|
+
* @deprecated Use getHomeFeed() — 동일한 개인화 피드(`/recommendations/feed`)를 반환합니다.
|
|
6917
6938
|
*/
|
|
6918
6939
|
async getRecommendations(limit) {
|
|
6919
6940
|
const prefix = this.getPublicPrefix();
|
|
6920
6941
|
const params = limit ? `?limit=${limit}` : "";
|
|
6921
6942
|
const response = await this.videoFetch(
|
|
6922
6943
|
"GET",
|
|
6923
|
-
`${prefix}/recommendations${params}`
|
|
6944
|
+
`${prefix}/recommendations/feed${params}`
|
|
6924
6945
|
);
|
|
6925
6946
|
return response.videos;
|
|
6926
6947
|
}
|
|
@@ -6932,7 +6953,7 @@ var VideoAPI = class {
|
|
|
6932
6953
|
const params = limit ? `?limit=${limit}` : "";
|
|
6933
6954
|
const response = await this.videoFetch(
|
|
6934
6955
|
"GET",
|
|
6935
|
-
`${prefix}/recommendations/
|
|
6956
|
+
`${prefix}/recommendations/feed${params}`
|
|
6936
6957
|
);
|
|
6937
6958
|
return response.videos;
|
|
6938
6959
|
}
|
|
@@ -6944,7 +6965,7 @@ var VideoAPI = class {
|
|
|
6944
6965
|
const params = limit ? `?limit=${limit}` : "";
|
|
6945
6966
|
const response = await this.videoFetch(
|
|
6946
6967
|
"GET",
|
|
6947
|
-
`${prefix}/
|
|
6968
|
+
`${prefix}/videos/${videoId}/related${params}`
|
|
6948
6969
|
);
|
|
6949
6970
|
return response.videos;
|
|
6950
6971
|
}
|
|
@@ -6965,9 +6986,17 @@ var VideoAPI = class {
|
|
|
6965
6986
|
*/
|
|
6966
6987
|
async submitFeedback(videoId, feedback) {
|
|
6967
6988
|
const prefix = this.getPublicPrefix();
|
|
6968
|
-
|
|
6989
|
+
if (feedback === "not_interested") {
|
|
6990
|
+
await this.videoFetch(
|
|
6991
|
+
"POST",
|
|
6992
|
+
`${prefix}/recommendations/not-interested/${videoId}`,
|
|
6993
|
+
{}
|
|
6994
|
+
);
|
|
6995
|
+
return;
|
|
6996
|
+
}
|
|
6997
|
+
await this.videoFetch("POST", `${prefix}/recommendations/interactions`, {
|
|
6969
6998
|
video_id: videoId,
|
|
6970
|
-
|
|
6999
|
+
type: "like"
|
|
6971
7000
|
});
|
|
6972
7001
|
}
|
|
6973
7002
|
};
|
|
@@ -7009,7 +7038,7 @@ var GameConfigAPI = class {
|
|
|
7009
7038
|
/**
|
|
7010
7039
|
* 단일 기능 활성화 — set() 의 편의 wrapper.
|
|
7011
7040
|
*
|
|
7012
|
-
* @example await cb.game.config.enable(appId, "
|
|
7041
|
+
* @example await cb.game.config.enable(appId, "matchqueue_enabled")
|
|
7013
7042
|
*/
|
|
7014
7043
|
async enable(appId, feature) {
|
|
7015
7044
|
return this.set(appId, { [feature]: true });
|
|
@@ -7667,7 +7696,7 @@ var GameAPI = class {
|
|
|
7667
7696
|
const response = await fetch(`${this.gameServerUrl}/v1/game/${id}/rooms/${roomId}/spectators`, {
|
|
7668
7697
|
method: "POST",
|
|
7669
7698
|
headers: { ...this.getHeaders(), "Content-Type": "application/json" },
|
|
7670
|
-
body: JSON.stringify({
|
|
7699
|
+
body: JSON.stringify({ user_id: playerId })
|
|
7671
7700
|
});
|
|
7672
7701
|
if (!response.ok) throw new Error(`Failed to join spectator: ${response.statusText}`);
|
|
7673
7702
|
return response.json();
|
|
@@ -10993,11 +11022,11 @@ var GameRoomTransport = class {
|
|
|
10993
11022
|
});
|
|
10994
11023
|
}
|
|
10995
11024
|
// Private methods
|
|
10996
|
-
send(type, data) {
|
|
11025
|
+
send(type, data, msgId) {
|
|
10997
11026
|
if (!this.transport?.isConnected()) {
|
|
10998
11027
|
throw new GameError({ code: "NOT_CONNECTED", message: "Not connected" });
|
|
10999
11028
|
}
|
|
11000
|
-
const message = JSON.stringify({ type, data });
|
|
11029
|
+
const message = JSON.stringify({ type, data, msg_id: msgId });
|
|
11001
11030
|
this.transport.send(message, true);
|
|
11002
11031
|
}
|
|
11003
11032
|
sendWithHandler(type, data, handler) {
|
|
@@ -11006,14 +11035,14 @@ var GameRoomTransport = class {
|
|
|
11006
11035
|
setTimeout(() => {
|
|
11007
11036
|
this.pendingHandlers.delete(id);
|
|
11008
11037
|
}, 1e4);
|
|
11009
|
-
this.send(type,
|
|
11038
|
+
this.send(type, data, id);
|
|
11010
11039
|
}
|
|
11011
11040
|
handleMessage(data) {
|
|
11012
11041
|
try {
|
|
11013
11042
|
const msg = JSON.parse(data);
|
|
11014
|
-
if (msg.
|
|
11015
|
-
const handler = this.pendingHandlers.get(msg.
|
|
11016
|
-
this.pendingHandlers.delete(msg.
|
|
11043
|
+
if (msg.msg_id && this.pendingHandlers.has(msg.msg_id)) {
|
|
11044
|
+
const handler = this.pendingHandlers.get(msg.msg_id);
|
|
11045
|
+
this.pendingHandlers.delete(msg.msg_id);
|
|
11017
11046
|
handler(msg);
|
|
11018
11047
|
return;
|
|
11019
11048
|
}
|