@teamlearners/clawops 0.39.0 → 0.41.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-UOUNMCXE.cjs → chunk-7ZFSDBM6.cjs} +4 -4
  7. package/dist/{chunk-UOUNMCXE.cjs.map → chunk-7ZFSDBM6.cjs.map} +1 -1
  8. package/dist/chunk-H2KILE5I.js +6 -0
  9. package/dist/{chunk-NDFDYCFM.js.map → chunk-H2KILE5I.js.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-W4XFMJFU.js → chunk-OS5WZMBK.js} +3 -3
  13. package/dist/{chunk-W4XFMJFU.js.map → chunk-OS5WZMBK.js.map} +1 -1
  14. package/dist/{chunk-54GBFYZT.js → chunk-SXXOAPMG.js} +2 -2
  15. package/dist/chunk-SXXOAPMG.js.map +1 -0
  16. package/dist/chunk-WTG2QGQU.cjs +8 -0
  17. package/dist/{chunk-FI2WH67N.cjs.map → chunk-WTG2QGQU.cjs.map} +1 -1
  18. package/dist/{client-B_GblPxW.d.cts → client-DfN4wQXU.d.cts} +228 -27
  19. package/dist/{client-B_GblPxW.d.ts → client-DfN4wQXU.d.ts} +228 -27
  20. package/dist/index.cjs +148 -52
  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 +120 -25
  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>;
@@ -261,9 +264,22 @@ declare class AssignmentLinks extends APIResource {
261
264
 
262
265
  declare const BlockedRecipientSchema: z.ZodObject<{
263
266
  id: z.ZodString;
264
- /** 국내 표기로 정규화된 번호 (예 '01012345678'). */
265
- number: z.ZodString;
266
- channel: z.ZodEnum<["call", "message"]>;
267
+ /**
268
+ * 수신거부한 상대. **채널과 무관하게 항상 이 칸에 들어갑니다** —
269
+ * `call`·`message` 면 국내 표기로 정규화된 전화번호(예 `'01012345678'`),
270
+ * `email` 이면 소문자로 정규화된 이메일 주소(예 `'kim@example.com'`).
271
+ *
272
+ * 채널이 늘어도 이 칸 하나만 읽으면 됩니다.
273
+ */
274
+ recipient: z.ZodString;
275
+ /**
276
+ * ⚠️ `email` 이 2026-09-07 에 추가됐습니다. 이 값을 **enum 으로 좁히지 마세요** —
277
+ * 서버가 채널을 늘리면 옛 SDK 가 파싱 단계에서 통째로 실패합니다. 실제로 그 일이
278
+ * 있었습니다: `['call','message']` 로 굳혀 둔 탓에, 이메일 항목이 하나라도 섞이면
279
+ * 목록 조회 전체가 깨졌습니다. 알려진 값은 `BlockedChannel` 로 노출하되 파싱은
280
+ * 열어 둡니다.
281
+ */
282
+ channel: z.ZodString;
267
283
  /** 지금 차단 중인지. 해제분도 이력으로 조회되므로 이 값으로 구분한다. */
268
284
  active: z.ZodBoolean;
269
285
  source: z.ZodString;
@@ -278,9 +294,22 @@ declare const BlockedRecipientSchema: z.ZodObject<{
278
294
  unblockedNote: z.ZodOptional<z.ZodNullable<z.ZodString>>;
279
295
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
280
296
  id: z.ZodString;
281
- /** 국내 표기로 정규화된 번호 (예 '01012345678'). */
282
- number: z.ZodString;
283
- channel: z.ZodEnum<["call", "message"]>;
297
+ /**
298
+ * 수신거부한 상대. **채널과 무관하게 항상 이 칸에 들어갑니다** —
299
+ * `call`·`message` 면 국내 표기로 정규화된 전화번호(예 `'01012345678'`),
300
+ * `email` 이면 소문자로 정규화된 이메일 주소(예 `'kim@example.com'`).
301
+ *
302
+ * 채널이 늘어도 이 칸 하나만 읽으면 됩니다.
303
+ */
304
+ recipient: z.ZodString;
305
+ /**
306
+ * ⚠️ `email` 이 2026-09-07 에 추가됐습니다. 이 값을 **enum 으로 좁히지 마세요** —
307
+ * 서버가 채널을 늘리면 옛 SDK 가 파싱 단계에서 통째로 실패합니다. 실제로 그 일이
308
+ * 있었습니다: `['call','message']` 로 굳혀 둔 탓에, 이메일 항목이 하나라도 섞이면
309
+ * 목록 조회 전체가 깨졌습니다. 알려진 값은 `BlockedChannel` 로 노출하되 파싱은
310
+ * 열어 둡니다.
311
+ */
312
+ channel: z.ZodString;
284
313
  /** 지금 차단 중인지. 해제분도 이력으로 조회되므로 이 값으로 구분한다. */
285
314
  active: z.ZodBoolean;
286
315
  source: z.ZodString;
@@ -295,9 +324,22 @@ declare const BlockedRecipientSchema: z.ZodObject<{
295
324
  unblockedNote: z.ZodOptional<z.ZodNullable<z.ZodString>>;
296
325
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
297
326
  id: z.ZodString;
298
- /** 국내 표기로 정규화된 번호 (예 '01012345678'). */
299
- number: z.ZodString;
300
- channel: z.ZodEnum<["call", "message"]>;
327
+ /**
328
+ * 수신거부한 상대. **채널과 무관하게 항상 이 칸에 들어갑니다** —
329
+ * `call`·`message` 면 국내 표기로 정규화된 전화번호(예 `'01012345678'`),
330
+ * `email` 이면 소문자로 정규화된 이메일 주소(예 `'kim@example.com'`).
331
+ *
332
+ * 채널이 늘어도 이 칸 하나만 읽으면 됩니다.
333
+ */
334
+ recipient: z.ZodString;
335
+ /**
336
+ * ⚠️ `email` 이 2026-09-07 에 추가됐습니다. 이 값을 **enum 으로 좁히지 마세요** —
337
+ * 서버가 채널을 늘리면 옛 SDK 가 파싱 단계에서 통째로 실패합니다. 실제로 그 일이
338
+ * 있었습니다: `['call','message']` 로 굳혀 둔 탓에, 이메일 항목이 하나라도 섞이면
339
+ * 목록 조회 전체가 깨졌습니다. 알려진 값은 `BlockedChannel` 로 노출하되 파싱은
340
+ * 열어 둡니다.
341
+ */
342
+ channel: z.ZodString;
301
343
  /** 지금 차단 중인지. 해제분도 이력으로 조회되므로 이 값으로 구분한다. */
302
344
  active: z.ZodBoolean;
303
345
  source: z.ZodString;
@@ -312,9 +354,23 @@ declare const BlockedRecipientSchema: z.ZodObject<{
312
354
  unblockedNote: z.ZodOptional<z.ZodNullable<z.ZodString>>;
313
355
  }, z.ZodTypeAny, "passthrough">>;
314
356
  type BlockedRecipient = z.infer<typeof BlockedRecipientSchema>;
315
- type BlockedChannel = BlockedRecipient['channel'];
357
+ /**
358
+ * 차단 채널. `call`=전화, `message`=문자(SMS/LMS/MMS 공통), `email`=이메일.
359
+ *
360
+ * 같은 상대라도 채널마다 별개 항목입니다 — 전화와 이메일을 모두 막으려면 두 번 등록합니다.
361
+ *
362
+ * ⚠️ 응답의 `channel` 은 `string` 입니다(위 참조). 이 타입은 **요청을 쓸 때의 도움말**이고,
363
+ * `(string & {})` 를 유니온에 두어 서버가 새 채널을 내놔도 타입이 막지 않게 했습니다.
364
+ */
365
+ type BlockedChannel = 'call' | 'message' | 'email' | (string & {});
316
366
  type BlockedRecipientStatus = 'active' | 'released' | 'all';
317
- type BlockedRecipientSource = 'api' | 'console' | 'import';
367
+ /**
368
+ * 접수 경로. 공개 API 로 등록하면 이 넷 중 하나입니다.
369
+ *
370
+ * ⚠️ 응답에는 **여기 없는 값도 옵니다** — `ars`(ARS 수신거부 9번), `sms`(문자 회신) 처럼
371
+ * 내부 접수 경로로 들어온 항목이 그렇습니다. 그래서 응답의 `source` 는 `string` 입니다.
372
+ */
373
+ type BlockedRecipientSource = 'api' | 'console' | 'import' | 'agent';
318
374
 
319
375
  type RequestOptions$2 = {
320
376
  extraHeaders?: Record<string, string>;
@@ -324,23 +380,30 @@ type RequestOptions$2 = {
324
380
  /**
325
381
  * 수신거부(DNC) 명단 리소스.
326
382
  *
327
- * 등록된 번호는 이 계정의 **발신**(전화·문자)에서 제외됩니다. 착신은 막지 않습니다 —
328
- * 그 번호에서 걸려오는 전화는 그대로 받습니다.
383
+ * 등록된 대상은 이 계정의 **발신**(전화·문자·이메일)에서 제외됩니다. 착신은 막지 않습니다 —
384
+ * 그 번호에서 걸려오는 전화도, 그 주소에서 오는 메일도 그대로 받습니다.
329
385
  *
330
- * 전화와 문자는 각각 따로 차단합니다. 같은 번호라도 채널마다 별개 항목이므로,
331
- * 막으려면 `channel` 을 바꿔 두 번 등록합니다.
386
+ * 채널은 각각 따로 차단합니다. 같은 상대라도 채널마다 별개 항목이므로, 전화와 이메일을
387
+ * 모두 막으려면 `channel` 을 바꿔 두 번 등록합니다.
388
+ *
389
+ * ⚠️ **채널마다 막는 방식이 다릅니다.**
390
+ * - 전화·문자: 수신거부 대상이면 그 발신 요청 **전체**가 `422 recipient_blocked` 로 거절됩니다.
391
+ * - 이메일: 차단된 수신자만 **빼고 나머지에게는 보냅니다.** 응답의 `suppressed` 에 빠진
392
+ * 주소가 담기므로, `2xx` 를 받아도 그 칸을 확인해야 누가 안 갔는지 알 수 있습니다.
393
+ * 수신자가 전원 걸렸을 때만 `422` 입니다.
332
394
  */
333
395
  declare class BlockedRecipients extends APIResource {
334
396
  /**
335
- * 번호를 수신거부 명단에 등록합니다.
397
+ * 수신거부 명단에 등록합니다.
336
398
  *
337
- * 하이픈·`+82` 표기 모두 허용되며 국내 표기로 정규화되어 저장됩니다.
399
+ * `recipient` 형식은 `channel` 정합니다 `call`·`message` 는 **전화번호**(하이픈·`+82`
400
+ * 표기 모두 허용, 국내 표기로 정규화되어 저장), `email` 은 **이메일 주소**(소문자로 정규화).
338
401
  *
339
- * **멱등입니다** — 이미 차단 중인 (번호, 채널)을 다시 등록해도 에러가 아니라 기존 항목을
402
+ * **멱등입니다** — 이미 차단 중인 (대상, 채널)을 다시 등록해도 에러가 아니라 기존 항목을
340
403
  * 돌려줍니다. 같은 사람이 수신거부를 두 번 요청하는 것은 정상 상황이기 때문입니다.
341
404
  */
342
405
  create(params: {
343
- number: string;
406
+ recipient: string;
344
407
  channel: BlockedChannel;
345
408
  source?: BlockedRecipientSource;
346
409
  sourceRef?: string;
@@ -352,7 +415,7 @@ declare class BlockedRecipients extends APIResource {
352
415
  */
353
416
  list(params?: {
354
417
  channel?: BlockedChannel;
355
- number?: string;
418
+ recipient?: string;
356
419
  status?: BlockedRecipientStatus;
357
420
  page?: number;
358
421
  pageSize?: number;
@@ -1117,6 +1180,41 @@ declare const KakaoBrandTemplateSchema: z.ZodObject<{
1117
1180
  updatedAt: z.ZodString;
1118
1181
  }, z.ZodTypeAny, "passthrough">>;
1119
1182
  type KakaoBrandTemplate = z.infer<typeof KakaoBrandTemplateSchema>;
1183
+ /**
1184
+ * 자유형 말풍선에 실을 이미지.
1185
+ *
1186
+ * ⭐ `id` 는 **ClawOps 리소스 ID** 다 — 벤더 파일 식별자가 아니다. 발송의
1187
+ * `brand.free.imageId` 에 이 값을 넣으면 서버가 벤더 값으로 바꿔 보낸다.
1188
+ */
1189
+ declare const KakaoBrandImageSchema: z.ZodObject<{
1190
+ id: z.ZodString;
1191
+ /** 업로드할 때 지정한 말풍선 유형. 규격이 유형마다 달라 다른 유형엔 재사용할 수 없다. */
1192
+ bubbleType: z.ZodType<BrandBubbleType>;
1193
+ /** `'main'` | `'sub'`. 서브는 와이드리스트형에만 있다(메인 2:1, 서브 1:1). */
1194
+ slot: z.ZodString;
1195
+ /** 업로드한 원본 파일 이름. */
1196
+ name: z.ZodNullable<z.ZodString>;
1197
+ createdAt: z.ZodString;
1198
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
1199
+ id: z.ZodString;
1200
+ /** 업로드할 때 지정한 말풍선 유형. 규격이 유형마다 달라 다른 유형엔 재사용할 수 없다. */
1201
+ bubbleType: z.ZodType<BrandBubbleType>;
1202
+ /** `'main'` | `'sub'`. 서브는 와이드리스트형에만 있다(메인 2:1, 서브 1:1). */
1203
+ slot: z.ZodString;
1204
+ /** 업로드한 원본 파일 이름. */
1205
+ name: z.ZodNullable<z.ZodString>;
1206
+ createdAt: z.ZodString;
1207
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
1208
+ id: z.ZodString;
1209
+ /** 업로드할 때 지정한 말풍선 유형. 규격이 유형마다 달라 다른 유형엔 재사용할 수 없다. */
1210
+ bubbleType: z.ZodType<BrandBubbleType>;
1211
+ /** `'main'` | `'sub'`. 서브는 와이드리스트형에만 있다(메인 2:1, 서브 1:1). */
1212
+ slot: z.ZodString;
1213
+ /** 업로드한 원본 파일 이름. */
1214
+ name: z.ZodNullable<z.ZodString>;
1215
+ createdAt: z.ZodString;
1216
+ }, z.ZodTypeAny, "passthrough">>;
1217
+ type KakaoBrandImage = z.infer<typeof KakaoBrandImageSchema>;
1120
1218
  /** 채널 업종 카테고리. **열린 집합이므로 코드에 하드코딩하지 말 것** — 이 응답이 정본이다. */
1121
1219
  declare const KakaoChannelCategorySchema: z.ZodObject<{
1122
1220
  /** 채널 연결의 `categoryCode` 에 그대로 보내는 값. */
@@ -1381,6 +1479,58 @@ declare class KakaoBrandTemplates extends APIResource {
1381
1479
  */
1382
1480
  list(params: KakaoBrandTemplateListParams, options?: RequestOptions$1): Promise<Page<KakaoBrandTemplate>>;
1383
1481
  }
1482
+ /**
1483
+ * 자유형 말풍선에 실을 이미지.
1484
+ *
1485
+ * ⭐ **업로드 한 번, 발송 여러 번.** 캠페인 하나에 수천 건이 같은 그림을 쓰므로 받은 `id` 를
1486
+ * 재사용한다 — 발송마다 다시 올릴 필요가 없다.
1487
+ *
1488
+ * ⚠️ **규격이 말풍선 유형마다 다르다.** 업로드할 때 준 `bubbleType` 과 다른 유형에 쓰면
1489
+ * 카카오가 발송 단계에서 거절한다 — 그 유형으로 다시 올려야 한다.
1490
+ */
1491
+ declare class KakaoBrandImages extends APIResource {
1492
+ private get _path();
1493
+ /**
1494
+ * 이미지를 올리고 발송에 쓸 `id` 를 받는다.
1495
+ *
1496
+ * ```ts
1497
+ * const image = await client.kakao.brandImages.upload({
1498
+ * file: readFileSync('banner.png'),
1499
+ * filename: 'banner.png',
1500
+ * bubbleType: 'WIDE',
1501
+ * });
1502
+ * await client.messages.create({
1503
+ * to: '01012345678',
1504
+ * from: '07012345678',
1505
+ * brand: {
1506
+ * channelId,
1507
+ * free: { chatBubbleType: 'WIDE', content: '신메뉴가 나왔어요.', imageId: image.id },
1508
+ * },
1509
+ * });
1510
+ * ```
1511
+ *
1512
+ * ⚠️ `TEXT` 는 이미지 자리가 없어 `400` 이다. 자동완성에 뜨지만 쓸 수 없다.
1513
+ *
1514
+ * ⚠️ **상한은 5MB 다.** 넘으면 `400`, 10MB 를 넘으면 업로드 검증기가 먼저 끊어 `413` 이고
1515
+ * **`code` 가 없다** — 즉 "너무 크다" 가 두 모양으로 온다.
1516
+ *
1517
+ * @param params.filename 원본 파일 이름. 목록에서 사람이 알아볼 유일한 단서다.
1518
+ * @param params.slot 와이드리스트형에서 작은 항목에 쓸 이미지면 `'sub'`. 기본은 `'main'`.
1519
+ */
1520
+ upload(params: {
1521
+ file: Blob | Uint8Array;
1522
+ filename: string;
1523
+ bubbleType: BrandBubbleType;
1524
+ slot?: string;
1525
+ }, options?: RequestOptions$1): Promise<{
1526
+ id: string;
1527
+ }>;
1528
+ /** 올려 둔 이미지 목록. **`id` 를 잃었을 때 되찾는 경로다.** */
1529
+ list(params?: {
1530
+ page?: number;
1531
+ pageSize?: number;
1532
+ }, options?: RequestOptions$1): Promise<Page<KakaoBrandImage>>;
1533
+ }
1384
1534
  /**
1385
1535
  * 카카오 알림톡·브랜드 메시지 관련 리소스.
1386
1536
  *
@@ -1392,6 +1542,8 @@ declare class Kakao extends APIResource {
1392
1542
  get templates(): KakaoTemplates;
1393
1543
  /** 브랜드 메시지 템플릿. 알림톡 템플릿(`templates`)과 **다른 표**다. */
1394
1544
  get brandTemplates(): KakaoBrandTemplates;
1545
+ /** 자유형 말풍선에 실을 이미지. 템플릿형은 이미지가 템플릿에 들어 있어 필요 없다. */
1546
+ get brandImages(): KakaoBrandImages;
1395
1547
  /**
1396
1548
  * 채널 연결 시 지정할 업종 카테고리 목록.
1397
1549
  *
@@ -1540,6 +1692,8 @@ interface KakaoSendParams {
1540
1692
  * 채워야 할 이름은 `kakao.templates.list()` 응답의 `variables` 가 알려준다.
1541
1693
  */
1542
1694
  variables?: Record<string, string>;
1695
+ /** 알림톡엔 자유형이 없다 — 브랜드와 한 조립 함수를 쓰기 위한 스탬프이기도 하다. */
1696
+ free?: never;
1543
1697
  }
1544
1698
  /** 알림톡이 발송 실패했을 때 대신 나갈 문자. */
1545
1699
  interface KakaoFallbackParams {
@@ -1569,10 +1723,12 @@ interface KakaoMessageCreateParams extends MessageCreateBaseParams {
1569
1723
  subject?: never;
1570
1724
  mediaUrl?: never;
1571
1725
  }
1572
- /** 브랜드 메시지 템플릿 지정. 구조(본문·버튼·이미지)는 등록한 템플릿이 정한다. */
1573
- interface BrandSendParams {
1726
+ interface BrandSendBaseParams {
1574
1727
  /** `kakao.channels.list()` 의 `data[].id` (ClawOps 리소스 ID). */
1575
1728
  channelId: string;
1729
+ }
1730
+ /** 템플릿형 — 구조(본문·버튼·이미지)는 등록한 템플릿이 정하고 요청은 값만 채운다. */
1731
+ interface BrandTemplateSendParams extends BrandSendBaseParams {
1576
1732
  /**
1577
1733
  * `kakao.brandTemplates.list()` 의 `data[].id` (ClawOps 리소스 ID).
1578
1734
  */
@@ -1583,7 +1739,43 @@ interface BrandSendParams {
1583
1739
  * 채워야 할 이름은 `kakao.brandTemplates.list()` 응답의 `variables` 가 알려준다.
1584
1740
  */
1585
1741
  variables?: Record<string, string>;
1742
+ free?: never;
1586
1743
  }
1744
+ /**
1745
+ * 자유형 — 말풍선을 요청이 직접 들고 간다. 템플릿을 등록하지 않아도 된다.
1746
+ *
1747
+ * 종료된 친구톡을 대신하는 방식이다.
1748
+ *
1749
+ * ⛔ **변수를 쓸 수 없다.** 치환해 줄 템플릿이 없어 `#{…}` 가 그대로 톡에 렌더되므로
1750
+ * 서버가 `400` 으로 막는다. 값을 채우려면 템플릿형을 쓴다.
1751
+ */
1752
+ interface BrandFreeSendParams extends BrandSendBaseParams {
1753
+ /**
1754
+ * 말풍선 몸통. **불투명 오브젝트다 — SDK 는 안을 검사하지 않는다.**
1755
+ *
1756
+ * ⛔ 칸마다 타이핑하지 않는 것이 의도다. 말풍선 규격표는 서버에 한 벌만 있고, SDK 가
1757
+ * 사본을 들면 카카오가 칸을 늘린 날 **SDK 가 조용히 깎는다.** 잘못된 몸통은
1758
+ * `400 VALIDATION`(도메인) 또는 `400`+`errors`(스펙)로 돌아온다.
1759
+ *
1760
+ * `chatBubbleType` 이 규격을 정한다. 이미지가 필요한 유형은
1761
+ * `kakao.brandImages.upload()` 로 먼저 올리고 받은 `id` 를 `imageId` 에 넣는다.
1762
+ *
1763
+ * ⚠️ `interface` 로 선언한 값은 `Record<string, unknown>` 에 대입되지 않는다(암묵 인덱스
1764
+ * 시그니처가 없다). `free: { ...myBubble }` 로 펼치거나 `type` 으로 선언할 것.
1765
+ */
1766
+ free: Record<string, unknown>;
1767
+ templateId?: never;
1768
+ variables?: never;
1769
+ }
1770
+ /**
1771
+ * 브랜드 메시지 발송 지정. **템플릿형(`templateId`)과 자유형(`free`)은 정확히 하나만**
1772
+ * 성립한다 — 둘 다 실으면 어느 쪽으로 나갈지 정해 줄 수 없고, 둘 다 없으면 보낼 말풍선이
1773
+ * 없다. 서버도 `400 invalid_input` 이다.
1774
+ *
1775
+ * ⛔ **평평한 optional 로 합치지 말 것.** `templateId?`·`free?` 로 두면 `{ channelId }`
1776
+ * 하나만 준 오타가 컴파일을 통과해 **운영 트래픽의 런타임 400** 이 된다.
1777
+ */
1778
+ type BrandSendParams = BrandTemplateSendParams | BrandFreeSendParams;
1587
1779
  /**
1588
1780
  * 카카오 브랜드 메시지 발송 파라미터.
1589
1781
  *
@@ -2059,7 +2251,16 @@ type ClawOpsErrorCode = 'invalid_phone' | 'invalid_type' | 'invalid_input' | 'fr
2059
2251
  /** 광고성이라 20:50~08:00(KST)에는 접수되지 않는다. 하루 11시간 동안 나오므로 재시도 스케줄링이 이 분기에 달린다. */
2060
2252
  | 'kakao_brand_night_blocked'
2061
2253
  /** 브랜드는 대체발송이 없다 — `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 & {});
2254
+ | 'kakao_fallback_not_allowed'
2255
+ /** 자유형 몸통에서 본문을 뽑지 못했다. 벤더는 최상위 `text` 가 비면 접수 뒤 실패시킨다. */
2256
+ | 'kakao_brand_body_empty'
2257
+ /**
2258
+ * 자유형 `imageId` 가 이 계정의 이미지가 아니다.
2259
+ *
2260
+ * ⚠️ 벤더 fileId 를 직접 실어도 이 코드다 — 공개 API 는 `kakao.brandImages.upload()` 가
2261
+ * 준 우리 id 만 받는다(그게 남의 이미지를 막는 유일한 관문이다).
2262
+ */
2263
+ | '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
2264
  declare class ClawOpsError extends Error {
2064
2265
  constructor(message: string);
2065
2266
  }
@@ -2263,4 +2464,4 @@ declare class ClawOps extends APIClient {
2263
2464
  accounts(accountId: string): AccountContext;
2264
2465
  }
2265
2466
 
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 };
2467
+ 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 };