@teamlearners/clawops 0.39.0 → 0.40.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.
Files changed (34) hide show
  1. package/README.md +60 -0
  2. package/dist/agent/index.cjs +77 -77
  3. package/dist/agent/index.js +4 -4
  4. package/dist/agent/livekit/index.cjs +9 -9
  5. package/dist/agent/livekit/index.js +2 -2
  6. package/dist/{chunk-W4XFMJFU.js → chunk-AYSW63CJ.js} +3 -3
  7. package/dist/{chunk-W4XFMJFU.js.map → chunk-AYSW63CJ.js.map} +1 -1
  8. package/dist/chunk-IEFCBBKV.cjs +8 -0
  9. package/dist/{chunk-FI2WH67N.cjs.map → chunk-IEFCBBKV.cjs.map} +1 -1
  10. package/dist/{chunk-OBGKLTIN.cjs → chunk-MXEZQRIL.cjs} +2 -2
  11. package/dist/chunk-MXEZQRIL.cjs.map +1 -0
  12. package/dist/{chunk-UOUNMCXE.cjs → chunk-PO5ACGWL.cjs} +4 -4
  13. package/dist/{chunk-UOUNMCXE.cjs.map → chunk-PO5ACGWL.cjs.map} +1 -1
  14. package/dist/chunk-R6UEIVYE.js +6 -0
  15. package/dist/{chunk-NDFDYCFM.js.map → chunk-R6UEIVYE.js.map} +1 -1
  16. package/dist/{chunk-54GBFYZT.js → chunk-SXXOAPMG.js} +2 -2
  17. package/dist/chunk-SXXOAPMG.js.map +1 -0
  18. package/dist/{client-B_GblPxW.d.cts → client-DOMZ2phc.d.cts} +148 -7
  19. package/dist/{client-B_GblPxW.d.ts → client-DOMZ2phc.d.ts} +148 -7
  20. package/dist/index.cjs +121 -36
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +93 -9
  25. package/dist/index.js.map +1 -1
  26. package/dist/solapi/index.cjs +7 -7
  27. package/dist/solapi/index.d.cts +2 -2
  28. package/dist/solapi/index.d.ts +2 -2
  29. package/dist/solapi/index.js +2 -2
  30. package/package.json +1 -1
  31. package/dist/chunk-54GBFYZT.js.map +0 -1
  32. package/dist/chunk-FI2WH67N.cjs +0 -8
  33. package/dist/chunk-NDFDYCFM.js +0 -6
  34. package/dist/chunk-OBGKLTIN.cjs.map +0 -1
@@ -18,14 +18,16 @@ declare class APIClient {
18
18
  constructor(options: APIClientOptions);
19
19
  private _buildHeaders;
20
20
  protected _send(method: string, path: string, options?: {
21
- body?: Record<string, unknown> | null;
21
+ /** `FormData` 그대로 보낸다(multipart) — 직렬화도 Content-Type 도 건드리지 않는다. */
22
+ body?: Record<string, unknown> | FormData | null;
22
23
  query?: Record<string, unknown> | null;
23
24
  extraHeaders?: Record<string, string>;
24
25
  extraQuery?: Record<string, unknown>;
25
26
  timeout?: number;
26
27
  }): Promise<Response>;
27
28
  protected _request<T>(method: string, path: string, options?: {
28
- body?: Record<string, unknown> | null;
29
+ /** `FormData` 그대로 보낸다(multipart) — 직렬화도 Content-Type 도 건드리지 않는다. */
30
+ body?: Record<string, unknown> | FormData | null;
29
31
  query?: Record<string, unknown> | null;
30
32
  castTo?: z.ZodType<T>;
31
33
  extraHeaders?: Record<string, string>;
@@ -43,7 +45,8 @@ declare class APIClient {
43
45
  timeout?: number;
44
46
  }): Promise<T>;
45
47
  _post<T>(path: string, options: {
46
- body?: Record<string, unknown> | null;
48
+ /** `FormData` 그대로 보낸다(multipart) — 직렬화도 Content-Type 도 건드리지 않는다. */
49
+ body?: Record<string, unknown> | FormData | null;
47
50
  castTo: z.ZodType<T>;
48
51
  extraHeaders?: Record<string, string>;
49
52
  extraQuery?: Record<string, unknown>;
@@ -1117,6 +1120,41 @@ declare const KakaoBrandTemplateSchema: z.ZodObject<{
1117
1120
  updatedAt: z.ZodString;
1118
1121
  }, z.ZodTypeAny, "passthrough">>;
1119
1122
  type KakaoBrandTemplate = z.infer<typeof KakaoBrandTemplateSchema>;
1123
+ /**
1124
+ * 자유형 말풍선에 실을 이미지.
1125
+ *
1126
+ * ⭐ `id` 는 **ClawOps 리소스 ID** 다 — 벤더 파일 식별자가 아니다. 발송의
1127
+ * `brand.free.imageId` 에 이 값을 넣으면 서버가 벤더 값으로 바꿔 보낸다.
1128
+ */
1129
+ declare const KakaoBrandImageSchema: z.ZodObject<{
1130
+ id: z.ZodString;
1131
+ /** 업로드할 때 지정한 말풍선 유형. 규격이 유형마다 달라 다른 유형엔 재사용할 수 없다. */
1132
+ bubbleType: z.ZodType<BrandBubbleType>;
1133
+ /** `'main'` | `'sub'`. 서브는 와이드리스트형에만 있다(메인 2:1, 서브 1:1). */
1134
+ slot: z.ZodString;
1135
+ /** 업로드한 원본 파일 이름. */
1136
+ name: z.ZodNullable<z.ZodString>;
1137
+ createdAt: z.ZodString;
1138
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
1139
+ id: z.ZodString;
1140
+ /** 업로드할 때 지정한 말풍선 유형. 규격이 유형마다 달라 다른 유형엔 재사용할 수 없다. */
1141
+ bubbleType: z.ZodType<BrandBubbleType>;
1142
+ /** `'main'` | `'sub'`. 서브는 와이드리스트형에만 있다(메인 2:1, 서브 1:1). */
1143
+ slot: z.ZodString;
1144
+ /** 업로드한 원본 파일 이름. */
1145
+ name: z.ZodNullable<z.ZodString>;
1146
+ createdAt: z.ZodString;
1147
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
1148
+ id: z.ZodString;
1149
+ /** 업로드할 때 지정한 말풍선 유형. 규격이 유형마다 달라 다른 유형엔 재사용할 수 없다. */
1150
+ bubbleType: z.ZodType<BrandBubbleType>;
1151
+ /** `'main'` | `'sub'`. 서브는 와이드리스트형에만 있다(메인 2:1, 서브 1:1). */
1152
+ slot: z.ZodString;
1153
+ /** 업로드한 원본 파일 이름. */
1154
+ name: z.ZodNullable<z.ZodString>;
1155
+ createdAt: z.ZodString;
1156
+ }, z.ZodTypeAny, "passthrough">>;
1157
+ type KakaoBrandImage = z.infer<typeof KakaoBrandImageSchema>;
1120
1158
  /** 채널 업종 카테고리. **열린 집합이므로 코드에 하드코딩하지 말 것** — 이 응답이 정본이다. */
1121
1159
  declare const KakaoChannelCategorySchema: z.ZodObject<{
1122
1160
  /** 채널 연결의 `categoryCode` 에 그대로 보내는 값. */
@@ -1381,6 +1419,58 @@ declare class KakaoBrandTemplates extends APIResource {
1381
1419
  */
1382
1420
  list(params: KakaoBrandTemplateListParams, options?: RequestOptions$1): Promise<Page<KakaoBrandTemplate>>;
1383
1421
  }
1422
+ /**
1423
+ * 자유형 말풍선에 실을 이미지.
1424
+ *
1425
+ * ⭐ **업로드 한 번, 발송 여러 번.** 캠페인 하나에 수천 건이 같은 그림을 쓰므로 받은 `id` 를
1426
+ * 재사용한다 — 발송마다 다시 올릴 필요가 없다.
1427
+ *
1428
+ * ⚠️ **규격이 말풍선 유형마다 다르다.** 업로드할 때 준 `bubbleType` 과 다른 유형에 쓰면
1429
+ * 카카오가 발송 단계에서 거절한다 — 그 유형으로 다시 올려야 한다.
1430
+ */
1431
+ declare class KakaoBrandImages extends APIResource {
1432
+ private get _path();
1433
+ /**
1434
+ * 이미지를 올리고 발송에 쓸 `id` 를 받는다.
1435
+ *
1436
+ * ```ts
1437
+ * const image = await client.kakao.brandImages.upload({
1438
+ * file: readFileSync('banner.png'),
1439
+ * filename: 'banner.png',
1440
+ * bubbleType: 'WIDE',
1441
+ * });
1442
+ * await client.messages.create({
1443
+ * to: '01012345678',
1444
+ * from: '07012345678',
1445
+ * brand: {
1446
+ * channelId,
1447
+ * free: { chatBubbleType: 'WIDE', content: '신메뉴가 나왔어요.', imageId: image.id },
1448
+ * },
1449
+ * });
1450
+ * ```
1451
+ *
1452
+ * ⚠️ `TEXT` 는 이미지 자리가 없어 `400` 이다. 자동완성에 뜨지만 쓸 수 없다.
1453
+ *
1454
+ * ⚠️ **상한은 5MB 다.** 넘으면 `400`, 10MB 를 넘으면 업로드 검증기가 먼저 끊어 `413` 이고
1455
+ * **`code` 가 없다** — 즉 "너무 크다" 가 두 모양으로 온다.
1456
+ *
1457
+ * @param params.filename 원본 파일 이름. 목록에서 사람이 알아볼 유일한 단서다.
1458
+ * @param params.slot 와이드리스트형에서 작은 항목에 쓸 이미지면 `'sub'`. 기본은 `'main'`.
1459
+ */
1460
+ upload(params: {
1461
+ file: Blob | Uint8Array;
1462
+ filename: string;
1463
+ bubbleType: BrandBubbleType;
1464
+ slot?: string;
1465
+ }, options?: RequestOptions$1): Promise<{
1466
+ id: string;
1467
+ }>;
1468
+ /** 올려 둔 이미지 목록. **`id` 를 잃었을 때 되찾는 경로다.** */
1469
+ list(params?: {
1470
+ page?: number;
1471
+ pageSize?: number;
1472
+ }, options?: RequestOptions$1): Promise<Page<KakaoBrandImage>>;
1473
+ }
1384
1474
  /**
1385
1475
  * 카카오 알림톡·브랜드 메시지 관련 리소스.
1386
1476
  *
@@ -1392,6 +1482,8 @@ declare class Kakao extends APIResource {
1392
1482
  get templates(): KakaoTemplates;
1393
1483
  /** 브랜드 메시지 템플릿. 알림톡 템플릿(`templates`)과 **다른 표**다. */
1394
1484
  get brandTemplates(): KakaoBrandTemplates;
1485
+ /** 자유형 말풍선에 실을 이미지. 템플릿형은 이미지가 템플릿에 들어 있어 필요 없다. */
1486
+ get brandImages(): KakaoBrandImages;
1395
1487
  /**
1396
1488
  * 채널 연결 시 지정할 업종 카테고리 목록.
1397
1489
  *
@@ -1540,6 +1632,8 @@ interface KakaoSendParams {
1540
1632
  * 채워야 할 이름은 `kakao.templates.list()` 응답의 `variables` 가 알려준다.
1541
1633
  */
1542
1634
  variables?: Record<string, string>;
1635
+ /** 알림톡엔 자유형이 없다 — 브랜드와 한 조립 함수를 쓰기 위한 스탬프이기도 하다. */
1636
+ free?: never;
1543
1637
  }
1544
1638
  /** 알림톡이 발송 실패했을 때 대신 나갈 문자. */
1545
1639
  interface KakaoFallbackParams {
@@ -1569,10 +1663,12 @@ interface KakaoMessageCreateParams extends MessageCreateBaseParams {
1569
1663
  subject?: never;
1570
1664
  mediaUrl?: never;
1571
1665
  }
1572
- /** 브랜드 메시지 템플릿 지정. 구조(본문·버튼·이미지)는 등록한 템플릿이 정한다. */
1573
- interface BrandSendParams {
1666
+ interface BrandSendBaseParams {
1574
1667
  /** `kakao.channels.list()` 의 `data[].id` (ClawOps 리소스 ID). */
1575
1668
  channelId: string;
1669
+ }
1670
+ /** 템플릿형 — 구조(본문·버튼·이미지)는 등록한 템플릿이 정하고 요청은 값만 채운다. */
1671
+ interface BrandTemplateSendParams extends BrandSendBaseParams {
1576
1672
  /**
1577
1673
  * `kakao.brandTemplates.list()` 의 `data[].id` (ClawOps 리소스 ID).
1578
1674
  */
@@ -1583,7 +1679,43 @@ interface BrandSendParams {
1583
1679
  * 채워야 할 이름은 `kakao.brandTemplates.list()` 응답의 `variables` 가 알려준다.
1584
1680
  */
1585
1681
  variables?: Record<string, string>;
1682
+ free?: never;
1683
+ }
1684
+ /**
1685
+ * 자유형 — 말풍선을 요청이 직접 들고 간다. 템플릿을 등록하지 않아도 된다.
1686
+ *
1687
+ * 종료된 친구톡을 대신하는 방식이다.
1688
+ *
1689
+ * ⛔ **변수를 쓸 수 없다.** 치환해 줄 템플릿이 없어 `#{…}` 가 그대로 톡에 렌더되므로
1690
+ * 서버가 `400` 으로 막는다. 값을 채우려면 템플릿형을 쓴다.
1691
+ */
1692
+ interface BrandFreeSendParams extends BrandSendBaseParams {
1693
+ /**
1694
+ * 말풍선 몸통. **불투명 오브젝트다 — SDK 는 안을 검사하지 않는다.**
1695
+ *
1696
+ * ⛔ 칸마다 타이핑하지 않는 것이 의도다. 말풍선 규격표는 서버에 한 벌만 있고, SDK 가
1697
+ * 사본을 들면 카카오가 칸을 늘린 날 **SDK 가 조용히 깎는다.** 잘못된 몸통은
1698
+ * `400 VALIDATION`(도메인) 또는 `400`+`errors`(스펙)로 돌아온다.
1699
+ *
1700
+ * `chatBubbleType` 이 규격을 정한다. 이미지가 필요한 유형은
1701
+ * `kakao.brandImages.upload()` 로 먼저 올리고 받은 `id` 를 `imageId` 에 넣는다.
1702
+ *
1703
+ * ⚠️ `interface` 로 선언한 값은 `Record<string, unknown>` 에 대입되지 않는다(암묵 인덱스
1704
+ * 시그니처가 없다). `free: { ...myBubble }` 로 펼치거나 `type` 으로 선언할 것.
1705
+ */
1706
+ free: Record<string, unknown>;
1707
+ templateId?: never;
1708
+ variables?: never;
1586
1709
  }
1710
+ /**
1711
+ * 브랜드 메시지 발송 지정. **템플릿형(`templateId`)과 자유형(`free`)은 정확히 하나만**
1712
+ * 성립한다 — 둘 다 실으면 어느 쪽으로 나갈지 정해 줄 수 없고, 둘 다 없으면 보낼 말풍선이
1713
+ * 없다. 서버도 `400 invalid_input` 이다.
1714
+ *
1715
+ * ⛔ **평평한 optional 로 합치지 말 것.** `templateId?`·`free?` 로 두면 `{ channelId }`
1716
+ * 하나만 준 오타가 컴파일을 통과해 **운영 트래픽의 런타임 400** 이 된다.
1717
+ */
1718
+ type BrandSendParams = BrandTemplateSendParams | BrandFreeSendParams;
1587
1719
  /**
1588
1720
  * 카카오 브랜드 메시지 발송 파라미터.
1589
1721
  *
@@ -2059,7 +2191,16 @@ type ClawOpsErrorCode = 'invalid_phone' | 'invalid_type' | 'invalid_input' | 'fr
2059
2191
  /** 광고성이라 20:50~08:00(KST)에는 접수되지 않는다. 하루 11시간 동안 나오므로 재시도 스케줄링이 이 분기에 달린다. */
2060
2192
  | 'kakao_brand_night_blocked'
2061
2193
  /** 브랜드는 대체발송이 없다 — `fallback` 을 실으면 이 코드다. */
2062
- | 'kakao_fallback_not_allowed' | 'KAKAO_TOKEN_INVALID' | 'KAKAO_CHANNEL_ALREADY_LINKED' | 'KAKAO_CHANNEL_REJECTED' | 'KAKAO_RATE_LIMITED' | 'KAKAO_PROVIDER_UNAVAILABLE' | 'VALIDATION' | 'NOT_FOUND' | (string & {});
2194
+ | 'kakao_fallback_not_allowed'
2195
+ /** 자유형 몸통에서 본문을 뽑지 못했다. 벤더는 최상위 `text` 가 비면 접수 뒤 실패시킨다. */
2196
+ | 'kakao_brand_body_empty'
2197
+ /**
2198
+ * 자유형 `imageId` 가 이 계정의 이미지가 아니다.
2199
+ *
2200
+ * ⚠️ 벤더 fileId 를 직접 실어도 이 코드다 — 공개 API 는 `kakao.brandImages.upload()` 가
2201
+ * 준 우리 id 만 받는다(그게 남의 이미지를 막는 유일한 관문이다).
2202
+ */
2203
+ | 'kakao_brand_image_not_found' | 'KAKAO_TOKEN_INVALID' | 'KAKAO_CHANNEL_ALREADY_LINKED' | 'KAKAO_CHANNEL_REJECTED' | 'KAKAO_RATE_LIMITED' | 'KAKAO_PROVIDER_UNAVAILABLE' | 'VALIDATION' | 'NOT_FOUND' | (string & {});
2063
2204
  declare class ClawOpsError extends Error {
2064
2205
  constructor(message: string);
2065
2206
  }
@@ -2263,4 +2404,4 @@ declare class ClawOps extends APIClient {
2263
2404
  accounts(accountId: string): AccountContext;
2264
2405
  }
2265
2406
 
2266
- export { type KakaoTemplateListParams as $, APIClient as A, BadRequestError as B, type Call as C, type CallListParams as D, type CallUpdateParams as E, Calls as F, ClawOps as G, ClawOpsError as H, type ClawOpsErrorCode as I, type ClawOpsOptions as J, ConflictError as K, InternalServerError as L, Kakao as M, type KakaoBrandTemplate as N, type KakaoBrandTemplateListParams as O, KakaoBrandTemplates as P, type KakaoChannel as Q, type KakaoChannelCategory as R, type KakaoChannelCategoryList as S, type KakaoChannelConnectParams as T, type KakaoChannelListParams as U, type KakaoChannelStatus as V, KakaoChannels as W, type KakaoFallbackParams as X, type KakaoMessageCreateParams as Y, type KakaoSendParams as Z, type KakaoTemplate as _, type APIClientOptions as a, KakaoTemplates as a0, type KakaoTokenRequest as a1, type KakaoTokenRequestParams as a2, type Message as a3, type MessageCreateParams as a4, type MessageListParams as a5, Messages as a6, NotFoundError as a7, type NumberCreateParams as a8, type NumberListItem as a9, type NumberUpdateParams as aa, type NumberUpdateResponse as ab, Numbers as ac, Page as ad, PermissionDeniedError as ae, type PhoneNumber as af, RateLimitError as ag, type RecordingDownload as ah, Recordings as ai, type RoutingType as aj, ServiceUnavailableError as ak, type SipCredential as al, SipCredentials as am, type SipEndpoint as an, SipEndpoints as ao, SolapiBridgeError as ap, type TextMessageCreateParams as aq, UnprocessableEntityError as ar, type WebhookLog as as, WebhookLogs as at, WebhookVerificationError as au, Webhooks as av, APIConnectionError as b, APIError as c, APIResponseValidationError as d, APIStatusError as e, APITimeoutError as f, AccountContext as g, AgentConnectionError as h, AgentError as i, type AssignmentLink as j, type AssignmentLinkAssignment as k, type AssignmentLinkCreateResponse as l, type AssignmentLinkStatus as m, AssignmentLinks as n, AuthenticationError as o, type BlockedChannel as p, type BlockedRecipient as q, type BlockedRecipientSource as r, type BlockedRecipientStatus as s, BlockedRecipients as t, type BrandBubbleType as u, type BrandMessageCreateParams as v, type BrandSendParams as w, type CallContextParam as x, type CallControlResponse as y, type CallCreateParams as z };
2407
+ export { type KakaoFallbackParams as $, APIClient as A, BadRequestError as B, type Call as C, type CallControlResponse as D, type CallCreateParams as E, type CallListParams as F, type CallUpdateParams as G, Calls as H, ClawOps as I, ClawOpsError as J, type ClawOpsErrorCode as K, type ClawOpsOptions as L, ConflictError as M, InternalServerError as N, Kakao as O, type KakaoBrandImage as P, KakaoBrandImages as Q, type KakaoBrandTemplate as R, type KakaoBrandTemplateListParams as S, KakaoBrandTemplates as T, type KakaoChannel as U, type KakaoChannelCategory as V, type KakaoChannelCategoryList as W, type KakaoChannelConnectParams as X, type KakaoChannelListParams as Y, type KakaoChannelStatus as Z, KakaoChannels as _, type APIClientOptions as a, type KakaoMessageCreateParams as a0, type KakaoSendParams as a1, type KakaoTemplate as a2, type KakaoTemplateListParams as a3, KakaoTemplates as a4, type KakaoTokenRequest as a5, type KakaoTokenRequestParams as a6, type Message as a7, type MessageCreateParams as a8, type MessageListParams as a9, Messages as aa, NotFoundError as ab, type NumberCreateParams as ac, type NumberListItem as ad, type NumberUpdateParams as ae, type NumberUpdateResponse as af, Numbers as ag, Page as ah, PermissionDeniedError as ai, type PhoneNumber as aj, RateLimitError as ak, type RecordingDownload as al, Recordings as am, type RoutingType as an, ServiceUnavailableError as ao, type SipCredential as ap, SipCredentials as aq, type SipEndpoint as ar, SipEndpoints as as, SolapiBridgeError as at, type TextMessageCreateParams as au, UnprocessableEntityError as av, type WebhookLog as aw, WebhookLogs as ax, WebhookVerificationError as ay, Webhooks as az, APIConnectionError as b, APIError as c, APIResponseValidationError as d, APIStatusError as e, APITimeoutError as f, AccountContext as g, AgentConnectionError as h, AgentError as i, type AssignmentLink as j, type AssignmentLinkAssignment as k, type AssignmentLinkCreateResponse as l, type AssignmentLinkStatus as m, AssignmentLinks as n, AuthenticationError as o, type BlockedChannel as p, type BlockedRecipient as q, type BlockedRecipientSource as r, type BlockedRecipientStatus as s, BlockedRecipients as t, type BrandBubbleType as u, type BrandFreeSendParams as v, type BrandMessageCreateParams as w, type BrandSendParams as x, type BrandTemplateSendParams as y, type CallContextParam as z };
package/dist/index.cjs CHANGED
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var chunkLLPMUDNE_cjs = require('./chunk-LLPMUDNE.cjs');
6
- var chunkOBGKLTIN_cjs = require('./chunk-OBGKLTIN.cjs');
7
- var chunkFI2WH67N_cjs = require('./chunk-FI2WH67N.cjs');
6
+ var chunkMXEZQRIL_cjs = require('./chunk-MXEZQRIL.cjs');
7
+ var chunkIEFCBBKV_cjs = require('./chunk-IEFCBBKV.cjs');
8
8
  var zod = require('zod');
9
9
  var crypto = require('crypto');
10
10
 
@@ -15,14 +15,19 @@ function validateBaseUrl(url) {
15
15
  try {
16
16
  parsed = new URL(url);
17
17
  } catch {
18
- throw new chunkOBGKLTIN_cjs.ClawOpsError(`Invalid base_url: ${url}`);
18
+ throw new chunkMXEZQRIL_cjs.ClawOpsError(`Invalid base_url: ${url}`);
19
19
  }
20
20
  if (parsed.protocol === "https:") return url;
21
21
  if (parsed.protocol === "http:" && LOCALHOST_HOSTS.has(parsed.hostname)) return url;
22
- throw new chunkOBGKLTIN_cjs.ClawOpsError(
22
+ throw new chunkMXEZQRIL_cjs.ClawOpsError(
23
23
  `base_url\uC740 HTTPS\uB97C \uC0AC\uC6A9\uD574\uC57C \uD569\uB2C8\uB2E4 (\uBC1B\uC740 \uAC12: '${url}'). \uB85C\uCEEC \uAC1C\uBC1C \uC2DC\uC5D0\uB294 http://localhost\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`
24
24
  );
25
25
  }
26
+ function serializeBody(body) {
27
+ if (body instanceof FormData) return { payload: body, contentType: null };
28
+ if (!body) return { payload: void 0, contentType: "application/json" };
29
+ return { payload: JSON.stringify(body), contentType: "application/json" };
30
+ }
26
31
  var APIClient = class {
27
32
  _apiKey;
28
33
  _baseURL;
@@ -43,7 +48,7 @@ var APIClient = class {
43
48
  Authorization: `Bearer ${this._apiKey}`,
44
49
  "Content-Type": "application/json",
45
50
  Accept: "application/json",
46
- "User-Agent": `claw-ops-node/${chunkFI2WH67N_cjs.VERSION}`,
51
+ "User-Agent": `claw-ops-node/${chunkIEFCBBKV_cjs.VERSION}`,
47
52
  ...this._defaultHeaders
48
53
  };
49
54
  if (extra) Object.assign(headers, extra);
@@ -51,6 +56,9 @@ var APIClient = class {
51
56
  }
52
57
  async _send(method2, path, options = {}) {
53
58
  const headers = this._buildHeaders(options.extraHeaders);
59
+ const { payload, contentType } = serializeBody(options.body);
60
+ if (contentType === null) delete headers["Content-Type"];
61
+ else headers["Content-Type"] = contentType;
54
62
  const params = new URLSearchParams();
55
63
  const queryObj = { ...options.query, ...options.extraQuery };
56
64
  for (const [k, v] of Object.entries(queryObj)) {
@@ -68,7 +76,7 @@ var APIClient = class {
68
76
  response = await this._fetch(url, {
69
77
  method: method2,
70
78
  headers,
71
- body: options.body ? JSON.stringify(options.body) : void 0,
79
+ body: payload,
72
80
  signal: controller.signal
73
81
  });
74
82
  } catch (err) {
@@ -79,14 +87,14 @@ var APIClient = class {
79
87
  await this._sleep(this._retryDelay(this._maxRetries - retriesLeft));
80
88
  continue;
81
89
  }
82
- throw new chunkOBGKLTIN_cjs.APITimeoutError({ method: method2, url });
90
+ throw new chunkMXEZQRIL_cjs.APITimeoutError({ method: method2, url });
83
91
  }
84
92
  if (retriesLeft > 0) {
85
93
  retriesLeft--;
86
94
  await this._sleep(this._retryDelay(this._maxRetries - retriesLeft));
87
95
  continue;
88
96
  }
89
- throw new chunkOBGKLTIN_cjs.APIConnectionError({ method: method2, url });
97
+ throw new chunkMXEZQRIL_cjs.APIConnectionError({ method: method2, url });
90
98
  } finally {
91
99
  clearTimeout(timeoutId);
92
100
  }
@@ -102,7 +110,7 @@ var APIClient = class {
102
110
  } catch {
103
111
  body = null;
104
112
  }
105
- throw chunkOBGKLTIN_cjs.makeStatusError(response.status, body, response.headers, { method: method2, url });
113
+ throw chunkMXEZQRIL_cjs.makeStatusError(response.status, body, response.headers, { method: method2, url });
106
114
  }
107
115
  }
108
116
  async _request(method2, path, options = {}) {
@@ -113,11 +121,11 @@ var APIClient = class {
113
121
  try {
114
122
  json = await response.json();
115
123
  } catch {
116
- throw new chunkOBGKLTIN_cjs.APIResponseValidationError({ status: response.status }, { method: method2, url });
124
+ throw new chunkMXEZQRIL_cjs.APIResponseValidationError({ status: response.status }, { method: method2, url });
117
125
  }
118
126
  const parsed = options.castTo.safeParse(json);
119
127
  if (!parsed.success) {
120
- throw new chunkOBGKLTIN_cjs.APIResponseValidationError({ status: response.status }, { method: method2, url });
128
+ throw new chunkMXEZQRIL_cjs.APIResponseValidationError({ status: response.status }, { method: method2, url });
121
129
  }
122
130
  return parsed.data;
123
131
  }
@@ -712,6 +720,16 @@ var KakaoBrandTemplateSchema = zod.z.object({
712
720
  createdAt: zod.z.string(),
713
721
  updatedAt: zod.z.string()
714
722
  }).passthrough();
723
+ var KakaoBrandImageSchema = zod.z.object({
724
+ id: zod.z.string(),
725
+ /** 업로드할 때 지정한 말풍선 유형. 규격이 유형마다 달라 다른 유형엔 재사용할 수 없다. */
726
+ bubbleType: zod.z.string(),
727
+ /** `'main'` | `'sub'`. 서브는 와이드리스트형에만 있다(메인 2:1, 서브 1:1). */
728
+ slot: zod.z.string(),
729
+ /** 업로드한 원본 파일 이름. */
730
+ name: zod.z.string().nullable(),
731
+ createdAt: zod.z.string()
732
+ }).passthrough();
715
733
  var KakaoChannelCategorySchema = zod.z.object({
716
734
  /** 채널 연결의 `categoryCode` 에 그대로 보내는 값. */
717
735
  code: zod.z.string(),
@@ -883,6 +901,63 @@ var KakaoBrandTemplates = class extends APIResource {
883
901
  return page;
884
902
  }
885
903
  };
904
+ var KakaoBrandImages = class extends APIResource {
905
+ get _path() {
906
+ return `${this._basePath}/kakao/brand-images`;
907
+ }
908
+ /**
909
+ * 이미지를 올리고 발송에 쓸 `id` 를 받는다.
910
+ *
911
+ * ```ts
912
+ * const image = await client.kakao.brandImages.upload({
913
+ * file: readFileSync('banner.png'),
914
+ * filename: 'banner.png',
915
+ * bubbleType: 'WIDE',
916
+ * });
917
+ * await client.messages.create({
918
+ * to: '01012345678',
919
+ * from: '07012345678',
920
+ * brand: {
921
+ * channelId,
922
+ * free: { chatBubbleType: 'WIDE', content: '신메뉴가 나왔어요.', imageId: image.id },
923
+ * },
924
+ * });
925
+ * ```
926
+ *
927
+ * ⚠️ `TEXT` 는 이미지 자리가 없어 `400` 이다. 자동완성에 뜨지만 쓸 수 없다.
928
+ *
929
+ * ⚠️ **상한은 5MB 다.** 넘으면 `400`, 10MB 를 넘으면 업로드 검증기가 먼저 끊어 `413` 이고
930
+ * **`code` 가 없다** — 즉 "너무 크다" 가 두 모양으로 온다.
931
+ *
932
+ * @param params.filename 원본 파일 이름. 목록에서 사람이 알아볼 유일한 단서다.
933
+ * @param params.slot 와이드리스트형에서 작은 항목에 쓸 이미지면 `'sub'`. 기본은 `'main'`.
934
+ */
935
+ async upload(params, options = {}) {
936
+ const form = new FormData();
937
+ const blob = params.file instanceof Blob ? params.file : new Blob([params.file]);
938
+ form.append("image", blob, params.filename);
939
+ form.append("bubbleType", params.bubbleType);
940
+ if (params.slot) form.append("slot", params.slot);
941
+ return this._client._post(this._path, {
942
+ body: form,
943
+ castTo: zod.z.object({ id: zod.z.string() }).passthrough(),
944
+ ...options
945
+ });
946
+ }
947
+ /** 올려 둔 이미지 목록. **`id` 를 잃었을 때 되찾는 경로다.** */
948
+ async list(params = {}, options = {}) {
949
+ const query = stripNotGiven({ page: params.page, pageSize: params.pageSize });
950
+ const path = this._path;
951
+ const raw = await this._client._get(path, {
952
+ castTo: PageSchema(KakaoBrandImageSchema),
953
+ query: Object.keys(query).length ? query : void 0,
954
+ ...options
955
+ });
956
+ const page = new Page(raw.data, raw.meta);
957
+ page._setClient(this._client, path, KakaoBrandImageSchema, query);
958
+ return page;
959
+ }
960
+ };
886
961
  var Kakao = class extends APIResource {
887
962
  get channels() {
888
963
  return new KakaoChannels(this._client, this._accountId);
@@ -894,6 +969,10 @@ var Kakao = class extends APIResource {
894
969
  get brandTemplates() {
895
970
  return new KakaoBrandTemplates(this._client, this._accountId);
896
971
  }
972
+ /** 자유형 말풍선에 실을 이미지. 템플릿형은 이미지가 템플릿에 들어 있어 필요 없다. */
973
+ get brandImages() {
974
+ return new KakaoBrandImages(this._client, this._accountId);
975
+ }
897
976
  /**
898
977
  * 채널 연결 시 지정할 업종 카테고리 목록.
899
978
  *
@@ -936,7 +1015,12 @@ var MessageSchema = zod.z.object({
936
1015
  }).passthrough();
937
1016
 
938
1017
  // src/resources/messages.ts
939
- var templateBlock = (p) => p && stripNotGiven({ ChannelId: p.channelId, TemplateId: p.templateId, Variables: p.variables });
1018
+ var sendBlock = (p) => p && stripNotGiven({
1019
+ ChannelId: p.channelId,
1020
+ TemplateId: p.templateId,
1021
+ Variables: p.variables,
1022
+ Free: p.free
1023
+ });
940
1024
  var Messages = class extends APIResource {
941
1025
  /**
942
1026
  * 문자(SMS/LMS/MMS) 또는 카카오 알림톡·브랜드 메시지를 발송합니다.
@@ -975,8 +1059,8 @@ var Messages = class extends APIResource {
975
1059
  MediaUrl: params.mediaUrl,
976
1060
  IdempotencyKey: params.idempotencyKey,
977
1061
  // 중첩 객체는 손으로 조립한다 — stripNotGiven 은 한 겹만 훑는다.
978
- Kakao: templateBlock(params.kakao),
979
- Brand: templateBlock(params.brand),
1062
+ Kakao: sendBlock(params.kakao),
1063
+ Brand: sendBlock(params.brand),
980
1064
  Fallback: params.fallback && stripNotGiven({
981
1065
  Type: params.fallback.type,
982
1066
  Subject: params.fallback.subject,
@@ -1295,7 +1379,7 @@ var AccountContext = class {
1295
1379
  return new Kakao(this._client, this._accountId);
1296
1380
  }
1297
1381
  };
1298
- var WebhookVerificationError = class extends chunkOBGKLTIN_cjs.ClawOpsError {
1382
+ var WebhookVerificationError = class extends chunkMXEZQRIL_cjs.ClawOpsError {
1299
1383
  constructor(message = "Webhook \uC11C\uBA85\uC774 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.") {
1300
1384
  super(message);
1301
1385
  this.name = "WebhookVerificationError";
@@ -1325,11 +1409,11 @@ var ClawOps = class extends APIClient {
1325
1409
  constructor(options = {}) {
1326
1410
  let apiKey = options.apiKey ?? process.env.CLAWOPS_API_KEY;
1327
1411
  if (!apiKey) {
1328
- throw new chunkOBGKLTIN_cjs.ClawOpsError("apiKey\uB97C \uC9C0\uC815\uD558\uAC70\uB098 CLAWOPS_API_KEY \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694.");
1412
+ throw new chunkMXEZQRIL_cjs.ClawOpsError("apiKey\uB97C \uC9C0\uC815\uD558\uAC70\uB098 CLAWOPS_API_KEY \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694.");
1329
1413
  }
1330
1414
  let accountId = options.accountId ?? process.env.CLAWOPS_ACCOUNT_ID;
1331
1415
  if (!accountId) {
1332
- throw new chunkOBGKLTIN_cjs.ClawOpsError("accountId\uB97C \uC9C0\uC815\uD558\uAC70\uB098 CLAWOPS_ACCOUNT_ID \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694.");
1416
+ throw new chunkMXEZQRIL_cjs.ClawOpsError("accountId\uB97C \uC9C0\uC815\uD558\uAC70\uB098 CLAWOPS_ACCOUNT_ID \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694.");
1333
1417
  }
1334
1418
  const baseURL = options.baseURL ?? process.env.CLAWOPS_BASE_URL ?? chunkLLPMUDNE_cjs.DEFAULT_BASE_URL;
1335
1419
  super({
@@ -1386,79 +1470,79 @@ var client_default_default = ClawOps;
1386
1470
 
1387
1471
  Object.defineProperty(exports, "APIConnectionError", {
1388
1472
  enumerable: true,
1389
- get: function () { return chunkOBGKLTIN_cjs.APIConnectionError; }
1473
+ get: function () { return chunkMXEZQRIL_cjs.APIConnectionError; }
1390
1474
  });
1391
1475
  Object.defineProperty(exports, "APIError", {
1392
1476
  enumerable: true,
1393
- get: function () { return chunkOBGKLTIN_cjs.APIError; }
1477
+ get: function () { return chunkMXEZQRIL_cjs.APIError; }
1394
1478
  });
1395
1479
  Object.defineProperty(exports, "APIResponseValidationError", {
1396
1480
  enumerable: true,
1397
- get: function () { return chunkOBGKLTIN_cjs.APIResponseValidationError; }
1481
+ get: function () { return chunkMXEZQRIL_cjs.APIResponseValidationError; }
1398
1482
  });
1399
1483
  Object.defineProperty(exports, "APIStatusError", {
1400
1484
  enumerable: true,
1401
- get: function () { return chunkOBGKLTIN_cjs.APIStatusError; }
1485
+ get: function () { return chunkMXEZQRIL_cjs.APIStatusError; }
1402
1486
  });
1403
1487
  Object.defineProperty(exports, "APITimeoutError", {
1404
1488
  enumerable: true,
1405
- get: function () { return chunkOBGKLTIN_cjs.APITimeoutError; }
1489
+ get: function () { return chunkMXEZQRIL_cjs.APITimeoutError; }
1406
1490
  });
1407
1491
  Object.defineProperty(exports, "AgentConnectionError", {
1408
1492
  enumerable: true,
1409
- get: function () { return chunkOBGKLTIN_cjs.AgentConnectionError; }
1493
+ get: function () { return chunkMXEZQRIL_cjs.AgentConnectionError; }
1410
1494
  });
1411
1495
  Object.defineProperty(exports, "AgentError", {
1412
1496
  enumerable: true,
1413
- get: function () { return chunkOBGKLTIN_cjs.AgentError; }
1497
+ get: function () { return chunkMXEZQRIL_cjs.AgentError; }
1414
1498
  });
1415
1499
  Object.defineProperty(exports, "AuthenticationError", {
1416
1500
  enumerable: true,
1417
- get: function () { return chunkOBGKLTIN_cjs.AuthenticationError; }
1501
+ get: function () { return chunkMXEZQRIL_cjs.AuthenticationError; }
1418
1502
  });
1419
1503
  Object.defineProperty(exports, "BadRequestError", {
1420
1504
  enumerable: true,
1421
- get: function () { return chunkOBGKLTIN_cjs.BadRequestError; }
1505
+ get: function () { return chunkMXEZQRIL_cjs.BadRequestError; }
1422
1506
  });
1423
1507
  Object.defineProperty(exports, "ClawOpsError", {
1424
1508
  enumerable: true,
1425
- get: function () { return chunkOBGKLTIN_cjs.ClawOpsError; }
1509
+ get: function () { return chunkMXEZQRIL_cjs.ClawOpsError; }
1426
1510
  });
1427
1511
  Object.defineProperty(exports, "ConflictError", {
1428
1512
  enumerable: true,
1429
- get: function () { return chunkOBGKLTIN_cjs.ConflictError; }
1513
+ get: function () { return chunkMXEZQRIL_cjs.ConflictError; }
1430
1514
  });
1431
1515
  Object.defineProperty(exports, "InternalServerError", {
1432
1516
  enumerable: true,
1433
- get: function () { return chunkOBGKLTIN_cjs.InternalServerError; }
1517
+ get: function () { return chunkMXEZQRIL_cjs.InternalServerError; }
1434
1518
  });
1435
1519
  Object.defineProperty(exports, "NotFoundError", {
1436
1520
  enumerable: true,
1437
- get: function () { return chunkOBGKLTIN_cjs.NotFoundError; }
1521
+ get: function () { return chunkMXEZQRIL_cjs.NotFoundError; }
1438
1522
  });
1439
1523
  Object.defineProperty(exports, "PermissionDeniedError", {
1440
1524
  enumerable: true,
1441
- get: function () { return chunkOBGKLTIN_cjs.PermissionDeniedError; }
1525
+ get: function () { return chunkMXEZQRIL_cjs.PermissionDeniedError; }
1442
1526
  });
1443
1527
  Object.defineProperty(exports, "RateLimitError", {
1444
1528
  enumerable: true,
1445
- get: function () { return chunkOBGKLTIN_cjs.RateLimitError; }
1529
+ get: function () { return chunkMXEZQRIL_cjs.RateLimitError; }
1446
1530
  });
1447
1531
  Object.defineProperty(exports, "ServiceUnavailableError", {
1448
1532
  enumerable: true,
1449
- get: function () { return chunkOBGKLTIN_cjs.ServiceUnavailableError; }
1533
+ get: function () { return chunkMXEZQRIL_cjs.ServiceUnavailableError; }
1450
1534
  });
1451
1535
  Object.defineProperty(exports, "SolapiBridgeError", {
1452
1536
  enumerable: true,
1453
- get: function () { return chunkOBGKLTIN_cjs.SolapiBridgeError; }
1537
+ get: function () { return chunkMXEZQRIL_cjs.SolapiBridgeError; }
1454
1538
  });
1455
1539
  Object.defineProperty(exports, "UnprocessableEntityError", {
1456
1540
  enumerable: true,
1457
- get: function () { return chunkOBGKLTIN_cjs.UnprocessableEntityError; }
1541
+ get: function () { return chunkMXEZQRIL_cjs.UnprocessableEntityError; }
1458
1542
  });
1459
1543
  Object.defineProperty(exports, "VERSION", {
1460
1544
  enumerable: true,
1461
- get: function () { return chunkFI2WH67N_cjs.VERSION; }
1545
+ get: function () { return chunkIEFCBBKV_cjs.VERSION; }
1462
1546
  });
1463
1547
  exports.APIClient = APIClient;
1464
1548
  exports.AccountContext = AccountContext;
@@ -1467,6 +1551,7 @@ exports.BlockedRecipients = BlockedRecipients;
1467
1551
  exports.Calls = Calls;
1468
1552
  exports.ClawOps = ClawOps;
1469
1553
  exports.Kakao = Kakao;
1554
+ exports.KakaoBrandImages = KakaoBrandImages;
1470
1555
  exports.KakaoBrandTemplates = KakaoBrandTemplates;
1471
1556
  exports.KakaoChannels = KakaoChannels;
1472
1557
  exports.KakaoTemplates = KakaoTemplates;