connectbase-client 5.1.0 → 5.2.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 +17 -0
- package/README.md +73 -0
- package/dist/index.d.mts +90 -1
- package/dist/index.d.ts +90 -1
- package/dist/index.js +33 -0
- package/dist/index.mjs +33 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
본 SDK 의 모든 주요 변경사항을 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/) 형식으로 기록합니다.
|
|
4
4
|
버전은 [Semantic Versioning](https://semver.org/lang/ko/) 을 따릅니다.
|
|
5
5
|
|
|
6
|
+
## [5.1.1] - 2026-07-30
|
|
7
|
+
|
|
8
|
+
### Docs — README 에 Server-side (Admin) 섹션 신설
|
|
9
|
+
|
|
10
|
+
**코드 변경 없음.** 빌드 산출물(`dist/`)은 5.1.0 과 동일하다.
|
|
11
|
+
|
|
12
|
+
README API Reference 가 클라이언트 모듈만 다루고 있어서, 앱 소유자 권한으로 호출하는 관리
|
|
13
|
+
API 가 npm 페이지에서 통째로 보이지 않았다. 5.1.0 에서 추가한 `cb.appMembers` 를 포함해
|
|
14
|
+
서버사이드 표면을 한 섹션으로 정리했다:
|
|
15
|
+
|
|
16
|
+
- `appMembers.list/get`(이메일 포함) · `roles.*` · `publicKey.*` · `payment.list` · `push.getStats`
|
|
17
|
+
- `service_role` + `management_scopes` 최소권한 모델과 스코프↔메서드 대응표 7종
|
|
18
|
+
- 브라우저(`cb_pk_` 단독)에서 호출할 수 없는 이유와, 멤버 본인 조회는 `cb.auth.getMe()` 라는 구분
|
|
19
|
+
- `cb_sk_` 단독은 401 이며 시크릿이 이 경로에 등장하지 않는다는 점
|
|
20
|
+
|
|
21
|
+
섹션의 모든 예제 시그니처는 발행된 타입 정의에 대해 `tsc --strict` 로 검증했다.
|
|
22
|
+
|
|
6
23
|
## [5.1.0] - 2026-07-30
|
|
7
24
|
|
|
8
25
|
### Added — 앱 멤버 관리자 조회 `cb.appMembers` (이메일 포함)
|
package/README.md
CHANGED
|
@@ -117,6 +117,7 @@ try {
|
|
|
117
117
|
- **Knowledge Base (RAG)**: Document indexing + BM25 search with nori 한국어 형태소. PDF / DOCX / text file upload via `addDocumentFromFile`
|
|
118
118
|
- **Endpoint**: Call your own GPU models on your own PC through one `cb_pk_*` key — ConnectBase forwards the payload as-is (dumb pipe)
|
|
119
119
|
- **Support**: End-user feedback/issue reporting — users send issues to app operators, AI auto-classifies summary/urgency/category
|
|
120
|
+
- **Server-side (Admin)**: App-owner APIs for members (incl. email), roles/RBAC, public keys, payments and push stats — via console JWT or a serverless function's `ctx.cbAdmin` with least-privilege `management_scopes`
|
|
120
121
|
- **CLI**: Command-line tool for deploying web storage and tunneling local services
|
|
121
122
|
|
|
122
123
|
## CLI
|
|
@@ -1335,6 +1336,78 @@ await cb.support.reportIssue({
|
|
|
1335
1336
|
|
|
1336
1337
|
발행자가 결과를 조회하는 채널은 후속 plan 에서 추가될 예정 — 현재는 운영자가 외부 webhook(이메일/Slack 등)으로 회신하는 방식 권장.
|
|
1337
1338
|
|
|
1339
|
+
### Server-side (Admin)
|
|
1340
|
+
|
|
1341
|
+
앱 소유자 권한으로 호출하는 **관리 API**. 위의 클라이언트 모듈과 달리 **브라우저에서 Public Key(`cb_pk_`) 단독으로는 호출할 수 없다** — 다른 회원의 개인정보나 키 발급 같은 표면이라, 콘솔 JWT 또는 서버리스 함수의 `ctx.cbAdmin` 컨텍스트가 필요하다. 잘못된 인증으로 호출하면 SDK 가 요청 전에 예외를 던진다.
|
|
1342
|
+
|
|
1343
|
+
함수에서 쓰려면 두 가지가 필요하다:
|
|
1344
|
+
|
|
1345
|
+
1. 함수 생성 시 `service_role: true` — 런타임이 `ctx.cbAdmin` 을 주입한다 (RLS 우회, 이 앱 스코프).
|
|
1346
|
+
2. `management_scopes` 에 필요한 스코프만 opt-in — 최소권한. 스코프 없이 호출하면 403.
|
|
1347
|
+
|
|
1348
|
+
| 스코프 | 열리는 메서드 |
|
|
1349
|
+
|---|---|
|
|
1350
|
+
| `app_member:read` | `appMembers.list` / `appMembers.get` — 멤버 목록·상세 (**이메일 포함**) |
|
|
1351
|
+
| `role:read` | `roles.list` / `roles.get` |
|
|
1352
|
+
| `role:manage` | `roles.create` / `roles.update` / `roles.assign` / `roles.delete` |
|
|
1353
|
+
| `payment:read` | `payment.list` — 결제 내역 |
|
|
1354
|
+
| `publickey:read` | `publicKey.getPublicKeys` |
|
|
1355
|
+
| `publickey:manage` | `publicKey.createPublicKey` / `updatePublicKey` / `deletePublicKey` |
|
|
1356
|
+
| `push:read` | `push.getStats` |
|
|
1357
|
+
|
|
1358
|
+
시크릿 키(`cb_sk_`)는 이 경로에 등장하지 않는다 — 함수가 service-role 토큰으로 키 없이 호출하고, 토큰은 클러스터를 벗어나지 않는다. `cb_sk_` 단독으로 관리 API 를 호출하면 401 이다.
|
|
1359
|
+
|
|
1360
|
+
```typescript
|
|
1361
|
+
// 함수 안에서 (service_role: true, management_scopes: ["app_member:read"])
|
|
1362
|
+
export async function handler(payload, ctx) {
|
|
1363
|
+
if (!ctx.cbAdmin) throw new Error('service_role not enabled')
|
|
1364
|
+
|
|
1365
|
+
// 문의로 들어온 이메일이 어느 회원인지 대조 (닉네임·이메일·로그인 identity 부분 일치)
|
|
1366
|
+
const found = await ctx.cbAdmin.appMembers.list(ctx.appId, { search: payload.email })
|
|
1367
|
+
if (found.total_count === 0) return { matched: false }
|
|
1368
|
+
|
|
1369
|
+
// 회원 상세 — 로그인 수단까지
|
|
1370
|
+
const member = await ctx.cbAdmin.appMembers.get(ctx.appId, found.app_members[0].id)
|
|
1371
|
+
return {
|
|
1372
|
+
matched: true,
|
|
1373
|
+
memberId: member.id,
|
|
1374
|
+
email: member.email,
|
|
1375
|
+
providers: member.identities.map((i) => i.type), // ['GOOGLE']
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
```
|
|
1379
|
+
|
|
1380
|
+
`appMembers.list` 의 `email` 은 `app_members.email` 컬럼이 우선이고, 비어 있으면 `EMAIL` identity 의 `provider_uid` 로 fallback 한다. 소셜 제공자가 이메일을 주지 않은 회원은 빈 문자열이다. `total_count` 는 `search` 필터를 반영하므로 페이지네이션에 그대로 쓸 수 있다.
|
|
1381
|
+
|
|
1382
|
+
**멤버가 자기 정보를 볼 때는 `cb.auth.getMe()` 를 쓴다.** `appMembers.*` 는 운영자 방향 조회 전용이고, 멤버 쓰기(생성·삭제·정지·수정)는 콘솔 전용이라 `app_member:read` 로 열리지 않는다.
|
|
1383
|
+
|
|
1384
|
+
```typescript
|
|
1385
|
+
// 역할(RBAC) 관리 — management_scopes: ["role:read", "role:manage"]
|
|
1386
|
+
const roles = await ctx.cbAdmin.roles.list(ctx.appId)
|
|
1387
|
+
const { id } = await ctx.cbAdmin.roles.create(ctx.appId, {
|
|
1388
|
+
title: '읽기전용 운영자',
|
|
1389
|
+
description: '조회만',
|
|
1390
|
+
})
|
|
1391
|
+
// assign 은 "이 역할을 가질 사용자 전체" 로 동기화한다 (추가가 아님)
|
|
1392
|
+
await ctx.cbAdmin.roles.assign(ctx.appId, id, ['user-uuid-1', 'user-uuid-2'])
|
|
1393
|
+
|
|
1394
|
+
// Public Key 관리 — management_scopes: ["publickey:read", "publickey:manage"]
|
|
1395
|
+
// payment_mode 로 키마다 결제 자격증명 모드를 고정할 수 있다 (QA 빌드에 test 키)
|
|
1396
|
+
const created = await ctx.cbAdmin.publicKey.createPublicKey(ctx.appId, {
|
|
1397
|
+
name: 'QA',
|
|
1398
|
+
payment_mode: 'test',
|
|
1399
|
+
})
|
|
1400
|
+
console.log(created.key) // 전체 키값은 이때만 볼 수 있다
|
|
1401
|
+
|
|
1402
|
+
// 결제 내역 — management_scopes: ["payment:read"]
|
|
1403
|
+
const payments = await ctx.cbAdmin.payment.list(ctx.appId, { status: 'paid', limit: 50 })
|
|
1404
|
+
|
|
1405
|
+
// 푸시 통계 — management_scopes: ["push:read"]
|
|
1406
|
+
const stats = await ctx.cbAdmin.push.getStats(ctx.appId)
|
|
1407
|
+
```
|
|
1408
|
+
|
|
1409
|
+
콘솔 JWT 로 브라우저/서버에서 직접 호출할 때는 같은 메서드를 `cb.appMembers.*`, `cb.roles.*`, `cb.publicKey.*` 로 쓴다 (스코프 대신 콘솔 RBAC 권한이 적용된다).
|
|
1410
|
+
|
|
1338
1411
|
## Types
|
|
1339
1412
|
|
|
1340
1413
|
### GameState
|
package/dist/index.d.mts
CHANGED
|
@@ -5511,6 +5511,29 @@ interface PreparePaymentRequest {
|
|
|
5511
5511
|
* 상품별로 세금 카테고리를 달리 할 때만 지정한다. Paddle 은 무시한다.
|
|
5512
5512
|
*/
|
|
5513
5513
|
provider_price_ref?: string;
|
|
5514
|
+
/**
|
|
5515
|
+
* 이 결제에 미리 적용할 할인/쿠폰 코드(MoR 전용, 선택).
|
|
5516
|
+
*
|
|
5517
|
+
* 쿠폰은 PG 대시보드(Dodo Discounts / Paddle Discounts)에서 발행한다 — ConnectBase 는 코드를
|
|
5518
|
+
* 전달만 하고 발행/한도/유효기간은 PG 설정이 권위다. Paddle 은 API 가 코드 대신 내부 ID 를
|
|
5519
|
+
* 받으므로 서버가 코드를 조회해 해소한다.
|
|
5520
|
+
*
|
|
5521
|
+
* 실패는 조용히 정가로 넘어가지 않고 400 으로 거절된다:
|
|
5522
|
+
* - `discount_code_invalid` — 없거나 만료/비활성 코드
|
|
5523
|
+
* - `discount_code_unsupported` — 할인 코드를 지원하지 않는 프로바이더(toss/stripe/payapp/paypal)
|
|
5524
|
+
*
|
|
5525
|
+
* 할인이 적용되면 확정 응답의 `amount` 는 **실제 청구액**(할인 후)이고 차감분은
|
|
5526
|
+
* `discount_amount` 로 온다.
|
|
5527
|
+
*/
|
|
5528
|
+
discount_code?: string;
|
|
5529
|
+
/**
|
|
5530
|
+
* 호스티드 결제창에서 **고객이 직접** 쿠폰을 입력하도록 허용할지(선택).
|
|
5531
|
+
*
|
|
5532
|
+
* 미지정이면 프로바이더 기본값을 따른다. Dodo 는 결제창마다 켜고 끌 수 있다.
|
|
5533
|
+
* Paddle 오버레이는 입력칸을 항상 노출해 숨길 수 없으므로 `false` 는 400
|
|
5534
|
+
* `discount_code_entry_unsupported` 로 거절된다.
|
|
5535
|
+
*/
|
|
5536
|
+
allow_discount_code?: boolean;
|
|
5514
5537
|
amount: number;
|
|
5515
5538
|
order_name: string;
|
|
5516
5539
|
order_id?: string;
|
|
@@ -5573,7 +5596,10 @@ interface ConfirmPaymentRequest {
|
|
|
5573
5596
|
interface ConfirmPaymentResponse {
|
|
5574
5597
|
payment_id: string;
|
|
5575
5598
|
order_id: string;
|
|
5599
|
+
/** **실제 청구된** 금액. 할인이 적용되면 준비 금액보다 작다. */
|
|
5576
5600
|
amount: number;
|
|
5601
|
+
/** 할인으로 차감된 금액(준비 금액 − 실제 청구액). 할인이 없으면 생략된다. */
|
|
5602
|
+
discount_amount?: number;
|
|
5577
5603
|
status: PaymentStatus;
|
|
5578
5604
|
method: string;
|
|
5579
5605
|
receipt_url?: string;
|
|
@@ -5610,6 +5636,13 @@ interface PaymentDetail {
|
|
|
5610
5636
|
settlement_currency?: string;
|
|
5611
5637
|
/** 청구 국가 ISO 3166-1 alpha-2 (MoR 제공 시) */
|
|
5612
5638
|
country?: string;
|
|
5639
|
+
/** 적용된 할인 코드 (준비 시 지정한 경우). */
|
|
5640
|
+
discount_code?: string;
|
|
5641
|
+
/**
|
|
5642
|
+
* 할인으로 차감된 금액. `amount` 는 이미 할인이 반영된 실제 청구액이므로,
|
|
5643
|
+
* 정가를 표시하려면 `amount + discount_amount` 로 복원한다.
|
|
5644
|
+
*/
|
|
5645
|
+
discount_amount?: number;
|
|
5613
5646
|
status: PaymentStatus;
|
|
5614
5647
|
payment_provider?: PaymentProvider;
|
|
5615
5648
|
/** 이 결제가 사용한 자격증명 모드 (test | live). */
|
|
@@ -5719,10 +5752,23 @@ declare class PaymentAPI {
|
|
|
5719
5752
|
* if (result.payment_provider === 'payapp' && result.payapp_pay_url) {
|
|
5720
5753
|
* window.location.href = result.payapp_pay_url
|
|
5721
5754
|
* }
|
|
5755
|
+
*
|
|
5756
|
+
* // 할인 코드 (MoR: dodo/paddle) — PG 대시보드에서 발행한 코드를 그대로 넘긴다.
|
|
5757
|
+
* const discounted = await cb.payment.prepare({
|
|
5758
|
+
* amount: 10000,
|
|
5759
|
+
* order_name: '프리미엄 1개월',
|
|
5760
|
+
* discount_code: 'LAUNCH50', // 미리 적용
|
|
5761
|
+
* allow_discount_code: true, // 결제창에서 고객이 직접 입력하는 것도 허용 (Dodo)
|
|
5762
|
+
* })
|
|
5763
|
+
* // 확정 후 confirm 응답의 amount 는 할인이 반영된 실제 청구액,
|
|
5764
|
+
* // discount_amount 는 차감분이다.
|
|
5722
5765
|
* ```
|
|
5723
5766
|
*
|
|
5724
5767
|
* @remarks
|
|
5725
5768
|
* PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
|
|
5769
|
+
*
|
|
5770
|
+
* 할인 코드는 MoR 프로바이더(dodo/paddle)에서만 지원됩니다. 그 외 프로바이더에 넘기면
|
|
5771
|
+
* 정가로 조용히 청구되지 않고 400 `discount_code_unsupported` 로 거절됩니다.
|
|
5726
5772
|
*/
|
|
5727
5773
|
prepare(data: PreparePaymentRequest): Promise<PreparePaymentResponse>;
|
|
5728
5774
|
/**
|
|
@@ -7687,8 +7733,31 @@ interface CreateSubscriptionRequest {
|
|
|
7687
7733
|
billing_cycle: BillingCycle;
|
|
7688
7734
|
/** 결제일 (monthly: 1-28일, weekly: 0-6 요일) */
|
|
7689
7735
|
billing_day?: number;
|
|
7690
|
-
/**
|
|
7736
|
+
/**
|
|
7737
|
+
* 트라이얼(무료 체험) 기간 (일).
|
|
7738
|
+
*
|
|
7739
|
+
* 빌링키 모델(toss/stripe)에서는 ConnectBase 스케줄러가 체험 종료일에 첫 청구를 건다.
|
|
7740
|
+
* MoR 은 PG 가 정기청구를 소유하므로 결제창 생성 시 체험 일수를 함께 보낸다:
|
|
7741
|
+
* - **Dodo**: 구독마다 지정 가능(0~10000일)
|
|
7742
|
+
* - **Paddle**: 트라이얼이 요금제(price)에 붙는 속성이라 구독마다 지정할 수 없다 →
|
|
7743
|
+
* 400 `trial_days_unsupported`. 체험이 설정된 price 를 Paddle 대시보드에서 따로 만들어 쓴다.
|
|
7744
|
+
*/
|
|
7691
7745
|
trial_days?: number;
|
|
7746
|
+
/**
|
|
7747
|
+
* 첫 결제에 적용할 할인/쿠폰 코드(MoR 전용, 선택).
|
|
7748
|
+
*
|
|
7749
|
+
* 쿠폰은 PG 대시보드에서 발행하며, 몇 주기까지 할인할지도 그쪽 설정이 정한다
|
|
7750
|
+
* (예: Dodo `subscription_cycles` 로 "3개월간 50%"). ConnectBase 는 코드만 전달한다.
|
|
7751
|
+
*
|
|
7752
|
+
* 400 `discount_code_invalid`(없거나 만료) / `discount_code_unsupported`(미지원 프로바이더).
|
|
7753
|
+
*/
|
|
7754
|
+
discount_code?: string;
|
|
7755
|
+
/**
|
|
7756
|
+
* 호스티드 결제창에서 고객이 직접 쿠폰을 입력하도록 허용할지(선택).
|
|
7757
|
+
* Paddle 오버레이는 항상 노출해 숨길 수 없으므로 `false` 는 400
|
|
7758
|
+
* `discount_code_entry_unsupported` 로 거절된다.
|
|
7759
|
+
*/
|
|
7760
|
+
allow_discount_code?: boolean;
|
|
7692
7761
|
/** 고객 이메일 */
|
|
7693
7762
|
customer_email?: string;
|
|
7694
7763
|
/** 고객 이름 */
|
|
@@ -8124,7 +8193,27 @@ declare class SubscriptionAPI {
|
|
|
8124
8193
|
* billing_day: 15, // 매월 15일 결제
|
|
8125
8194
|
* trial_days: 7 // 7일 무료 체험
|
|
8126
8195
|
* })
|
|
8196
|
+
*
|
|
8197
|
+
* // MoR(dodo/paddle) 구독 + 할인 코드
|
|
8198
|
+
* const promo = await client.subscription.create({
|
|
8199
|
+
* plan_name: '프리미엄 플랜',
|
|
8200
|
+
* amount: 9900,
|
|
8201
|
+
* billing_cycle: 'monthly',
|
|
8202
|
+
* provider_price_ref: 'pdt_xxxxx', // PG 카탈로그의 recurring 상품
|
|
8203
|
+
* discount_code: 'LAUNCH50', // 첫 결제에 적용 (몇 주기까지인지는 PG 쿠폰 설정이 결정)
|
|
8204
|
+
* trial_days: 14, // Dodo 만 지원 — Paddle 은 400 trial_days_unsupported
|
|
8205
|
+
* })
|
|
8127
8206
|
* ```
|
|
8207
|
+
*
|
|
8208
|
+
* @remarks
|
|
8209
|
+
* 할인 코드(`discount_code`)와 `trial_days` 의 프로바이더 지원 범위가 다릅니다:
|
|
8210
|
+
* - **Dodo**: 할인 코드 O, 결제창 쿠폰 입력 토글 O, 구독별 체험 일수 O
|
|
8211
|
+
* - **Paddle**: 할인 코드 O(코드→내부 ID 자동 해소), 쿠폰 입력칸은 항상 노출(숨김 불가),
|
|
8212
|
+
* 체험은 요금제(price) 속성이라 구독별 지정 불가
|
|
8213
|
+
* - **toss/stripe/payapp/paypal**: 할인 코드 미지원(400), 체험은 ConnectBase 스케줄러가 처리
|
|
8214
|
+
*
|
|
8215
|
+
* 지원하지 않는 조합은 무시되지 않고 400 으로 거절됩니다 — "쿠폰을 넣었는데 정가 청구",
|
|
8216
|
+
* "체험을 줬는데 즉시 청구" 를 만들지 않기 위함입니다.
|
|
8128
8217
|
*/
|
|
8129
8218
|
create(data: CreateSubscriptionRequest): Promise<SubscriptionResponse>;
|
|
8130
8219
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -5511,6 +5511,29 @@ interface PreparePaymentRequest {
|
|
|
5511
5511
|
* 상품별로 세금 카테고리를 달리 할 때만 지정한다. Paddle 은 무시한다.
|
|
5512
5512
|
*/
|
|
5513
5513
|
provider_price_ref?: string;
|
|
5514
|
+
/**
|
|
5515
|
+
* 이 결제에 미리 적용할 할인/쿠폰 코드(MoR 전용, 선택).
|
|
5516
|
+
*
|
|
5517
|
+
* 쿠폰은 PG 대시보드(Dodo Discounts / Paddle Discounts)에서 발행한다 — ConnectBase 는 코드를
|
|
5518
|
+
* 전달만 하고 발행/한도/유효기간은 PG 설정이 권위다. Paddle 은 API 가 코드 대신 내부 ID 를
|
|
5519
|
+
* 받으므로 서버가 코드를 조회해 해소한다.
|
|
5520
|
+
*
|
|
5521
|
+
* 실패는 조용히 정가로 넘어가지 않고 400 으로 거절된다:
|
|
5522
|
+
* - `discount_code_invalid` — 없거나 만료/비활성 코드
|
|
5523
|
+
* - `discount_code_unsupported` — 할인 코드를 지원하지 않는 프로바이더(toss/stripe/payapp/paypal)
|
|
5524
|
+
*
|
|
5525
|
+
* 할인이 적용되면 확정 응답의 `amount` 는 **실제 청구액**(할인 후)이고 차감분은
|
|
5526
|
+
* `discount_amount` 로 온다.
|
|
5527
|
+
*/
|
|
5528
|
+
discount_code?: string;
|
|
5529
|
+
/**
|
|
5530
|
+
* 호스티드 결제창에서 **고객이 직접** 쿠폰을 입력하도록 허용할지(선택).
|
|
5531
|
+
*
|
|
5532
|
+
* 미지정이면 프로바이더 기본값을 따른다. Dodo 는 결제창마다 켜고 끌 수 있다.
|
|
5533
|
+
* Paddle 오버레이는 입력칸을 항상 노출해 숨길 수 없으므로 `false` 는 400
|
|
5534
|
+
* `discount_code_entry_unsupported` 로 거절된다.
|
|
5535
|
+
*/
|
|
5536
|
+
allow_discount_code?: boolean;
|
|
5514
5537
|
amount: number;
|
|
5515
5538
|
order_name: string;
|
|
5516
5539
|
order_id?: string;
|
|
@@ -5573,7 +5596,10 @@ interface ConfirmPaymentRequest {
|
|
|
5573
5596
|
interface ConfirmPaymentResponse {
|
|
5574
5597
|
payment_id: string;
|
|
5575
5598
|
order_id: string;
|
|
5599
|
+
/** **실제 청구된** 금액. 할인이 적용되면 준비 금액보다 작다. */
|
|
5576
5600
|
amount: number;
|
|
5601
|
+
/** 할인으로 차감된 금액(준비 금액 − 실제 청구액). 할인이 없으면 생략된다. */
|
|
5602
|
+
discount_amount?: number;
|
|
5577
5603
|
status: PaymentStatus;
|
|
5578
5604
|
method: string;
|
|
5579
5605
|
receipt_url?: string;
|
|
@@ -5610,6 +5636,13 @@ interface PaymentDetail {
|
|
|
5610
5636
|
settlement_currency?: string;
|
|
5611
5637
|
/** 청구 국가 ISO 3166-1 alpha-2 (MoR 제공 시) */
|
|
5612
5638
|
country?: string;
|
|
5639
|
+
/** 적용된 할인 코드 (준비 시 지정한 경우). */
|
|
5640
|
+
discount_code?: string;
|
|
5641
|
+
/**
|
|
5642
|
+
* 할인으로 차감된 금액. `amount` 는 이미 할인이 반영된 실제 청구액이므로,
|
|
5643
|
+
* 정가를 표시하려면 `amount + discount_amount` 로 복원한다.
|
|
5644
|
+
*/
|
|
5645
|
+
discount_amount?: number;
|
|
5613
5646
|
status: PaymentStatus;
|
|
5614
5647
|
payment_provider?: PaymentProvider;
|
|
5615
5648
|
/** 이 결제가 사용한 자격증명 모드 (test | live). */
|
|
@@ -5719,10 +5752,23 @@ declare class PaymentAPI {
|
|
|
5719
5752
|
* if (result.payment_provider === 'payapp' && result.payapp_pay_url) {
|
|
5720
5753
|
* window.location.href = result.payapp_pay_url
|
|
5721
5754
|
* }
|
|
5755
|
+
*
|
|
5756
|
+
* // 할인 코드 (MoR: dodo/paddle) — PG 대시보드에서 발행한 코드를 그대로 넘긴다.
|
|
5757
|
+
* const discounted = await cb.payment.prepare({
|
|
5758
|
+
* amount: 10000,
|
|
5759
|
+
* order_name: '프리미엄 1개월',
|
|
5760
|
+
* discount_code: 'LAUNCH50', // 미리 적용
|
|
5761
|
+
* allow_discount_code: true, // 결제창에서 고객이 직접 입력하는 것도 허용 (Dodo)
|
|
5762
|
+
* })
|
|
5763
|
+
* // 확정 후 confirm 응답의 amount 는 할인이 반영된 실제 청구액,
|
|
5764
|
+
* // discount_amount 는 차감분이다.
|
|
5722
5765
|
* ```
|
|
5723
5766
|
*
|
|
5724
5767
|
* @remarks
|
|
5725
5768
|
* PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
|
|
5769
|
+
*
|
|
5770
|
+
* 할인 코드는 MoR 프로바이더(dodo/paddle)에서만 지원됩니다. 그 외 프로바이더에 넘기면
|
|
5771
|
+
* 정가로 조용히 청구되지 않고 400 `discount_code_unsupported` 로 거절됩니다.
|
|
5726
5772
|
*/
|
|
5727
5773
|
prepare(data: PreparePaymentRequest): Promise<PreparePaymentResponse>;
|
|
5728
5774
|
/**
|
|
@@ -7687,8 +7733,31 @@ interface CreateSubscriptionRequest {
|
|
|
7687
7733
|
billing_cycle: BillingCycle;
|
|
7688
7734
|
/** 결제일 (monthly: 1-28일, weekly: 0-6 요일) */
|
|
7689
7735
|
billing_day?: number;
|
|
7690
|
-
/**
|
|
7736
|
+
/**
|
|
7737
|
+
* 트라이얼(무료 체험) 기간 (일).
|
|
7738
|
+
*
|
|
7739
|
+
* 빌링키 모델(toss/stripe)에서는 ConnectBase 스케줄러가 체험 종료일에 첫 청구를 건다.
|
|
7740
|
+
* MoR 은 PG 가 정기청구를 소유하므로 결제창 생성 시 체험 일수를 함께 보낸다:
|
|
7741
|
+
* - **Dodo**: 구독마다 지정 가능(0~10000일)
|
|
7742
|
+
* - **Paddle**: 트라이얼이 요금제(price)에 붙는 속성이라 구독마다 지정할 수 없다 →
|
|
7743
|
+
* 400 `trial_days_unsupported`. 체험이 설정된 price 를 Paddle 대시보드에서 따로 만들어 쓴다.
|
|
7744
|
+
*/
|
|
7691
7745
|
trial_days?: number;
|
|
7746
|
+
/**
|
|
7747
|
+
* 첫 결제에 적용할 할인/쿠폰 코드(MoR 전용, 선택).
|
|
7748
|
+
*
|
|
7749
|
+
* 쿠폰은 PG 대시보드에서 발행하며, 몇 주기까지 할인할지도 그쪽 설정이 정한다
|
|
7750
|
+
* (예: Dodo `subscription_cycles` 로 "3개월간 50%"). ConnectBase 는 코드만 전달한다.
|
|
7751
|
+
*
|
|
7752
|
+
* 400 `discount_code_invalid`(없거나 만료) / `discount_code_unsupported`(미지원 프로바이더).
|
|
7753
|
+
*/
|
|
7754
|
+
discount_code?: string;
|
|
7755
|
+
/**
|
|
7756
|
+
* 호스티드 결제창에서 고객이 직접 쿠폰을 입력하도록 허용할지(선택).
|
|
7757
|
+
* Paddle 오버레이는 항상 노출해 숨길 수 없으므로 `false` 는 400
|
|
7758
|
+
* `discount_code_entry_unsupported` 로 거절된다.
|
|
7759
|
+
*/
|
|
7760
|
+
allow_discount_code?: boolean;
|
|
7692
7761
|
/** 고객 이메일 */
|
|
7693
7762
|
customer_email?: string;
|
|
7694
7763
|
/** 고객 이름 */
|
|
@@ -8124,7 +8193,27 @@ declare class SubscriptionAPI {
|
|
|
8124
8193
|
* billing_day: 15, // 매월 15일 결제
|
|
8125
8194
|
* trial_days: 7 // 7일 무료 체험
|
|
8126
8195
|
* })
|
|
8196
|
+
*
|
|
8197
|
+
* // MoR(dodo/paddle) 구독 + 할인 코드
|
|
8198
|
+
* const promo = await client.subscription.create({
|
|
8199
|
+
* plan_name: '프리미엄 플랜',
|
|
8200
|
+
* amount: 9900,
|
|
8201
|
+
* billing_cycle: 'monthly',
|
|
8202
|
+
* provider_price_ref: 'pdt_xxxxx', // PG 카탈로그의 recurring 상품
|
|
8203
|
+
* discount_code: 'LAUNCH50', // 첫 결제에 적용 (몇 주기까지인지는 PG 쿠폰 설정이 결정)
|
|
8204
|
+
* trial_days: 14, // Dodo 만 지원 — Paddle 은 400 trial_days_unsupported
|
|
8205
|
+
* })
|
|
8127
8206
|
* ```
|
|
8207
|
+
*
|
|
8208
|
+
* @remarks
|
|
8209
|
+
* 할인 코드(`discount_code`)와 `trial_days` 의 프로바이더 지원 범위가 다릅니다:
|
|
8210
|
+
* - **Dodo**: 할인 코드 O, 결제창 쿠폰 입력 토글 O, 구독별 체험 일수 O
|
|
8211
|
+
* - **Paddle**: 할인 코드 O(코드→내부 ID 자동 해소), 쿠폰 입력칸은 항상 노출(숨김 불가),
|
|
8212
|
+
* 체험은 요금제(price) 속성이라 구독별 지정 불가
|
|
8213
|
+
* - **toss/stripe/payapp/paypal**: 할인 코드 미지원(400), 체험은 ConnectBase 스케줄러가 처리
|
|
8214
|
+
*
|
|
8215
|
+
* 지원하지 않는 조합은 무시되지 않고 400 으로 거절됩니다 — "쿠폰을 넣었는데 정가 청구",
|
|
8216
|
+
* "체험을 줬는데 즉시 청구" 를 만들지 않기 위함입니다.
|
|
8128
8217
|
*/
|
|
8129
8218
|
create(data: CreateSubscriptionRequest): Promise<SubscriptionResponse>;
|
|
8130
8219
|
/**
|
package/dist/index.js
CHANGED
|
@@ -6138,10 +6138,23 @@ var PaymentAPI = class {
|
|
|
6138
6138
|
* if (result.payment_provider === 'payapp' && result.payapp_pay_url) {
|
|
6139
6139
|
* window.location.href = result.payapp_pay_url
|
|
6140
6140
|
* }
|
|
6141
|
+
*
|
|
6142
|
+
* // 할인 코드 (MoR: dodo/paddle) — PG 대시보드에서 발행한 코드를 그대로 넘긴다.
|
|
6143
|
+
* const discounted = await cb.payment.prepare({
|
|
6144
|
+
* amount: 10000,
|
|
6145
|
+
* order_name: '프리미엄 1개월',
|
|
6146
|
+
* discount_code: 'LAUNCH50', // 미리 적용
|
|
6147
|
+
* allow_discount_code: true, // 결제창에서 고객이 직접 입력하는 것도 허용 (Dodo)
|
|
6148
|
+
* })
|
|
6149
|
+
* // 확정 후 confirm 응답의 amount 는 할인이 반영된 실제 청구액,
|
|
6150
|
+
* // discount_amount 는 차감분이다.
|
|
6141
6151
|
* ```
|
|
6142
6152
|
*
|
|
6143
6153
|
* @remarks
|
|
6144
6154
|
* PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
|
|
6155
|
+
*
|
|
6156
|
+
* 할인 코드는 MoR 프로바이더(dodo/paddle)에서만 지원됩니다. 그 외 프로바이더에 넘기면
|
|
6157
|
+
* 정가로 조용히 청구되지 않고 400 `discount_code_unsupported` 로 거절됩니다.
|
|
6145
6158
|
*/
|
|
6146
6159
|
async prepare(data) {
|
|
6147
6160
|
const prefix = this.getPublicPrefix();
|
|
@@ -9023,7 +9036,27 @@ var SubscriptionAPI = class {
|
|
|
9023
9036
|
* billing_day: 15, // 매월 15일 결제
|
|
9024
9037
|
* trial_days: 7 // 7일 무료 체험
|
|
9025
9038
|
* })
|
|
9039
|
+
*
|
|
9040
|
+
* // MoR(dodo/paddle) 구독 + 할인 코드
|
|
9041
|
+
* const promo = await client.subscription.create({
|
|
9042
|
+
* plan_name: '프리미엄 플랜',
|
|
9043
|
+
* amount: 9900,
|
|
9044
|
+
* billing_cycle: 'monthly',
|
|
9045
|
+
* provider_price_ref: 'pdt_xxxxx', // PG 카탈로그의 recurring 상품
|
|
9046
|
+
* discount_code: 'LAUNCH50', // 첫 결제에 적용 (몇 주기까지인지는 PG 쿠폰 설정이 결정)
|
|
9047
|
+
* trial_days: 14, // Dodo 만 지원 — Paddle 은 400 trial_days_unsupported
|
|
9048
|
+
* })
|
|
9026
9049
|
* ```
|
|
9050
|
+
*
|
|
9051
|
+
* @remarks
|
|
9052
|
+
* 할인 코드(`discount_code`)와 `trial_days` 의 프로바이더 지원 범위가 다릅니다:
|
|
9053
|
+
* - **Dodo**: 할인 코드 O, 결제창 쿠폰 입력 토글 O, 구독별 체험 일수 O
|
|
9054
|
+
* - **Paddle**: 할인 코드 O(코드→내부 ID 자동 해소), 쿠폰 입력칸은 항상 노출(숨김 불가),
|
|
9055
|
+
* 체험은 요금제(price) 속성이라 구독별 지정 불가
|
|
9056
|
+
* - **toss/stripe/payapp/paypal**: 할인 코드 미지원(400), 체험은 ConnectBase 스케줄러가 처리
|
|
9057
|
+
*
|
|
9058
|
+
* 지원하지 않는 조합은 무시되지 않고 400 으로 거절됩니다 — "쿠폰을 넣었는데 정가 청구",
|
|
9059
|
+
* "체험을 줬는데 즉시 청구" 를 만들지 않기 위함입니다.
|
|
9027
9060
|
*/
|
|
9028
9061
|
async create(data) {
|
|
9029
9062
|
const prefix = this.getPublicPrefix();
|
package/dist/index.mjs
CHANGED
|
@@ -6089,10 +6089,23 @@ var PaymentAPI = class {
|
|
|
6089
6089
|
* if (result.payment_provider === 'payapp' && result.payapp_pay_url) {
|
|
6090
6090
|
* window.location.href = result.payapp_pay_url
|
|
6091
6091
|
* }
|
|
6092
|
+
*
|
|
6093
|
+
* // 할인 코드 (MoR: dodo/paddle) — PG 대시보드에서 발행한 코드를 그대로 넘긴다.
|
|
6094
|
+
* const discounted = await cb.payment.prepare({
|
|
6095
|
+
* amount: 10000,
|
|
6096
|
+
* order_name: '프리미엄 1개월',
|
|
6097
|
+
* discount_code: 'LAUNCH50', // 미리 적용
|
|
6098
|
+
* allow_discount_code: true, // 결제창에서 고객이 직접 입력하는 것도 허용 (Dodo)
|
|
6099
|
+
* })
|
|
6100
|
+
* // 확정 후 confirm 응답의 amount 는 할인이 반영된 실제 청구액,
|
|
6101
|
+
* // discount_amount 는 차감분이다.
|
|
6092
6102
|
* ```
|
|
6093
6103
|
*
|
|
6094
6104
|
* @remarks
|
|
6095
6105
|
* PayApp 은 `customer_phone` 이 필수입니다(결제요청 수신 번호). 미지정 시 서버가 거부합니다.
|
|
6106
|
+
*
|
|
6107
|
+
* 할인 코드는 MoR 프로바이더(dodo/paddle)에서만 지원됩니다. 그 외 프로바이더에 넘기면
|
|
6108
|
+
* 정가로 조용히 청구되지 않고 400 `discount_code_unsupported` 로 거절됩니다.
|
|
6096
6109
|
*/
|
|
6097
6110
|
async prepare(data) {
|
|
6098
6111
|
const prefix = this.getPublicPrefix();
|
|
@@ -8974,7 +8987,27 @@ var SubscriptionAPI = class {
|
|
|
8974
8987
|
* billing_day: 15, // 매월 15일 결제
|
|
8975
8988
|
* trial_days: 7 // 7일 무료 체험
|
|
8976
8989
|
* })
|
|
8990
|
+
*
|
|
8991
|
+
* // MoR(dodo/paddle) 구독 + 할인 코드
|
|
8992
|
+
* const promo = await client.subscription.create({
|
|
8993
|
+
* plan_name: '프리미엄 플랜',
|
|
8994
|
+
* amount: 9900,
|
|
8995
|
+
* billing_cycle: 'monthly',
|
|
8996
|
+
* provider_price_ref: 'pdt_xxxxx', // PG 카탈로그의 recurring 상품
|
|
8997
|
+
* discount_code: 'LAUNCH50', // 첫 결제에 적용 (몇 주기까지인지는 PG 쿠폰 설정이 결정)
|
|
8998
|
+
* trial_days: 14, // Dodo 만 지원 — Paddle 은 400 trial_days_unsupported
|
|
8999
|
+
* })
|
|
8977
9000
|
* ```
|
|
9001
|
+
*
|
|
9002
|
+
* @remarks
|
|
9003
|
+
* 할인 코드(`discount_code`)와 `trial_days` 의 프로바이더 지원 범위가 다릅니다:
|
|
9004
|
+
* - **Dodo**: 할인 코드 O, 결제창 쿠폰 입력 토글 O, 구독별 체험 일수 O
|
|
9005
|
+
* - **Paddle**: 할인 코드 O(코드→내부 ID 자동 해소), 쿠폰 입력칸은 항상 노출(숨김 불가),
|
|
9006
|
+
* 체험은 요금제(price) 속성이라 구독별 지정 불가
|
|
9007
|
+
* - **toss/stripe/payapp/paypal**: 할인 코드 미지원(400), 체험은 ConnectBase 스케줄러가 처리
|
|
9008
|
+
*
|
|
9009
|
+
* 지원하지 않는 조합은 무시되지 않고 400 으로 거절됩니다 — "쿠폰을 넣었는데 정가 청구",
|
|
9010
|
+
* "체험을 줬는데 즉시 청구" 를 만들지 않기 위함입니다.
|
|
8978
9011
|
*/
|
|
8979
9012
|
async create(data) {
|
|
8980
9013
|
const prefix = this.getPublicPrefix();
|