@teamlearners/clawops 0.35.0 → 0.37.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 (50) hide show
  1. package/README.md +92 -4
  2. package/dist/agent/index.cjs +85 -416
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts +2 -2
  5. package/dist/agent/index.d.ts +2 -2
  6. package/dist/agent/index.js +6 -341
  7. package/dist/agent/index.js.map +1 -1
  8. package/dist/agent/livekit/index.cjs +9 -8
  9. package/dist/agent/livekit/index.cjs.map +1 -1
  10. package/dist/agent/livekit/index.d.cts +1 -1
  11. package/dist/agent/livekit/index.d.ts +1 -1
  12. package/dist/agent/livekit/index.js +2 -1
  13. package/dist/agent/livekit/index.js.map +1 -1
  14. package/dist/{base-C3yzF1e0.d.cts → base-BalWsEyb.d.cts} +31 -2
  15. package/dist/{base-C3yzF1e0.d.ts → base-BalWsEyb.d.ts} +31 -2
  16. package/dist/{chunk-4YLSDMLL.js → chunk-2OGQSWTW.js} +372 -3
  17. package/dist/chunk-2OGQSWTW.js.map +1 -0
  18. package/dist/{chunk-M6BYGYJO.js → chunk-35XJNMFU.js} +3 -6
  19. package/dist/chunk-35XJNMFU.js.map +1 -0
  20. package/dist/{chunk-QD2ZY4UP.cjs → chunk-7TEOYLZI.cjs} +375 -2
  21. package/dist/chunk-7TEOYLZI.cjs.map +1 -0
  22. package/dist/chunk-CKPVV6SZ.js +6 -0
  23. package/dist/chunk-CKPVV6SZ.js.map +1 -0
  24. package/dist/chunk-EYI3ULDU.cjs +8 -0
  25. package/dist/chunk-EYI3ULDU.cjs.map +1 -0
  26. package/dist/{chunk-TVDUOKJD.cjs → chunk-IYSPOOKH.cjs} +14 -2
  27. package/dist/chunk-IYSPOOKH.cjs.map +1 -0
  28. package/dist/{chunk-NT6ZS3TQ.cjs → chunk-LLPMUDNE.cjs} +2 -6
  29. package/dist/chunk-LLPMUDNE.cjs.map +1 -0
  30. package/dist/{chunk-36JABW7P.js → chunk-VYGIWHRU.js} +14 -2
  31. package/dist/chunk-VYGIWHRU.js.map +1 -0
  32. package/dist/{client-CKaAfPlF.d.cts → client-DKsEma11.d.cts} +580 -21
  33. package/dist/{client-CKaAfPlF.d.ts → client-DKsEma11.d.ts} +580 -21
  34. package/dist/index.cjs +311 -42
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +1 -1
  37. package/dist/index.d.ts +1 -1
  38. package/dist/index.js +273 -7
  39. package/dist/index.js.map +1 -1
  40. package/dist/solapi/index.cjs +7 -7
  41. package/dist/solapi/index.d.cts +2 -2
  42. package/dist/solapi/index.d.ts +2 -2
  43. package/dist/solapi/index.js +2 -2
  44. package/package.json +1 -1
  45. package/dist/chunk-36JABW7P.js.map +0 -1
  46. package/dist/chunk-4YLSDMLL.js.map +0 -1
  47. package/dist/chunk-M6BYGYJO.js.map +0 -1
  48. package/dist/chunk-NT6ZS3TQ.cjs.map +0 -1
  49. package/dist/chunk-QD2ZY4UP.cjs.map +0 -1
  50. package/dist/chunk-TVDUOKJD.cjs.map +0 -1
package/README.md CHANGED
@@ -372,6 +372,77 @@ for await (const m of (await client.messages.list()).autoPagingIter()) {
372
372
  const detail = await client.messages.get('MG0123456789abcdef');
373
373
  ```
374
374
 
375
+ ### 카카오 알림톡 (Kakao)
376
+
377
+ 승인된 템플릿으로 알림톡을 보냅니다. 발송에 필요한 채널·템플릿 ID 는 SDK 로 조회합니다.
378
+
379
+ ```typescript
380
+ // 1. 연결된 카카오 채널
381
+ const channels = await client.kakao.channels.list({ status: 'connected' });
382
+ const channel = channels.data[0];
383
+
384
+ // 2. 그 채널의 템플릿 — sendable: true 인 것만 보낼 수 있습니다
385
+ const templates = await client.kakao.templates.list({ channelId: channel.id });
386
+ const template = templates.data.find((t) => t.sendable);
387
+ console.log(template.variables); // ['#{고객명}'] — 이 목록을 모두 채워야 합니다
388
+
389
+ // 3. 발송
390
+ const msg = await client.messages.create({
391
+ to: '01012345678',
392
+ from: '07052358010',
393
+ kakao: {
394
+ channelId: channel.id,
395
+ templateId: template.id,
396
+ variables: { 고객명: '홍길동' }, // '#{고객명}' 표기도 받습니다
397
+ },
398
+ fallback: { body: '주문이 접수되었습니다.' },
399
+ });
400
+ console.log(msg.type); // 'ata'
401
+ ```
402
+
403
+ **본문은 템플릿이 정합니다.** 알림톡에는 `body`·`subject`·`mediaUrl` 을 실을 수 없고(컴파일
404
+ 에러입니다), 버튼·아이템 리스트·강조 문구는 카카오 검수를 받은 그대로 나갑니다 — 발송 요청으로
405
+ 바꿀 수 없습니다. 요청에서 바꿀 수 있는 것은 `variables` 값뿐입니다.
406
+
407
+ **대체발송(`fallback`)은 별도의 메시지 1건으로 기록되고 문자 단가로 청구됩니다.** 생략하면
408
+ 템플릿 본문이 그대로 문자로 나가고, `fallback: { disabled: true }` 면 알림톡 실패가 그대로
409
+ 실패로 남습니다.
410
+
411
+ 변수를 빠뜨리면 발송 전에 `400 kakao_variable_missing` 으로 막힙니다(카카오는 이런 요청도
412
+ 접수한 뒤 조용히 실패시키므로 ClawOps 가 미리 잡습니다). 사유는 `e.code` 로 분기하세요.
413
+
414
+ #### 채널 연결
415
+
416
+ 채널 연결은 두 단계입니다 — 인증번호는 카카오 비즈니스에 등록된 **담당자 휴대전화로만** 갑니다.
417
+
418
+ ```typescript
419
+ const categories = await client.kakao.channelCategories();
420
+
421
+ const requested = await client.kakao.channels.requestToken({
422
+ searchId: '@example',
423
+ phoneNumber: '010-1234-5678',
424
+ });
425
+ console.log(requested.phoneNumberMasked); // '010-****-5678'
426
+
427
+ // 담당자가 받은 인증번호로 완료 (이미 연결된 채널이면 인증번호를 쓰지 않고 기존 연결을 돌려줍니다)
428
+ const channel = await client.kakao.channels.connect({
429
+ searchId: requested.searchId,
430
+ phoneNumber: '010-1234-5678',
431
+ categoryCode: categories.data[0].code,
432
+ token: '394812',
433
+ });
434
+ ```
435
+
436
+ ⚠️ `connect()` 가 **타임아웃되면 재호출하지 마세요.** 이미 연결에 성공했을 수 있습니다 —
437
+ `channels.retrieve(id)` 로 실제 등록 여부를 확인하세요(이 조회는 몇 번을 불러도 안전합니다).
438
+ 연결에 **실패해도 인증번호는 소모되므로** 원인을 해결한 뒤 `requestToken()` 부터 다시 시작해야 합니다.
439
+
440
+ ⚠️ `channels.disconnect(id)` 는 **되돌릴 수 없고 그 채널의 알림톡 템플릿까지 함께 삭제합니다.**
441
+ 템플릿은 카카오 검수를 다시 받아야 합니다.
442
+
443
+ `channels.list()` 는 저장된 연결 정보를 그대로 돌려줍니다(빠릅니다). 카카오 쪽 상태까지 실제로
444
+ 확인하는 것은 `channels.retrieve()` 뿐이며, 이 호출이 `status` 를 갱신합니다.
445
+
375
446
  ### 솔라피(SOLAPI) 호환 — 문자만 ClawOps 로
376
447
 
377
448
  이미 솔라피 SDK 로 작성된 코드를 **그대로 두고** 문자(SMS/LMS/MMS)만 ClawOps 로 보냅니다.
@@ -646,16 +717,33 @@ try {
646
717
  const call = await client.calls.create({ to: '01012345678', from: '07052358010', url: 'https://...' });
647
718
  } catch (e) {
648
719
  if (e instanceof BadRequestError) {
649
- console.log(`잘못된 요청: ${e.statusCode} - ${JSON.stringify(e.body)}`);
720
+ console.log(`잘못된 요청: ${e.status} - ${JSON.stringify(e.body)}`);
650
721
  } else if (e instanceof AuthenticationError) {
651
- console.log(`유효하지 않은 API 키: ${e.statusCode}`);
722
+ console.log(`유효하지 않은 API 키: ${e.status}`);
652
723
  } else if (e instanceof NotFoundError) {
653
- console.log(`리소스를 찾을 수 없음: ${e.statusCode}`);
724
+ console.log(`리소스를 찾을 수 없음: ${e.status}`);
654
725
  }
655
726
  }
656
727
  ```
657
728
 
658
- 모든 에러는 `ClawOpsError`를 상속합니다. HTTP 에러는 `statusCode`, `body` 속성을 제공합니다.
729
+ 모든 에러는 `ClawOpsError`를 상속합니다. HTTP 에러는 `status`, `code`, `body` 속성을 제공합니다.
730
+
731
+ **사유는 `code` 로 분기하세요** — 한 상태 코드가 서로 다른 사유를 담고, 한글 메시지는 바뀔 수
732
+ 있습니다. 서버가 `code` 를 싣지 않은 응답에서는 `undefined` 입니다.
733
+
734
+ ```typescript
735
+ import { UnprocessableEntityError } from '@teamlearners/clawops';
736
+
737
+ try {
738
+ await client.messages.create({ to, from, kakao: { channelId, templateId, variables } });
739
+ } catch (e) {
740
+ if (e instanceof UnprocessableEntityError && e.code === 'recipient_blocked') {
741
+ // 수신거부 — 재시도하면 안 됩니다
742
+ } else if (e instanceof BadRequestError && e.code === 'kakao_variable_missing') {
743
+ // 템플릿 변수 누락 — templates.list() 의 variables 를 다시 확인하세요
744
+ }
745
+ }
746
+ ```
659
747
 
660
748
  | 에러 | 상태 코드 |
661
749
  | -------------------------- | --------- |