@teamlearners/clawops 0.35.0 → 0.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/README.md +92 -4
- package/dist/agent/index.cjs +10 -10
- package/dist/agent/index.js +2 -2
- package/dist/{chunk-TVDUOKJD.cjs → chunk-IYSPOOKH.cjs} +14 -2
- package/dist/chunk-IYSPOOKH.cjs.map +1 -0
- package/dist/{chunk-NT6ZS3TQ.cjs → chunk-LKFNV2GI.cjs} +3 -3
- package/dist/{chunk-NT6ZS3TQ.cjs.map → chunk-LKFNV2GI.cjs.map} +1 -1
- package/dist/{chunk-36JABW7P.js → chunk-VYGIWHRU.js} +14 -2
- package/dist/chunk-VYGIWHRU.js.map +1 -0
- package/dist/{chunk-M6BYGYJO.js → chunk-XL2VWU36.js} +3 -3
- package/dist/{chunk-M6BYGYJO.js.map → chunk-XL2VWU36.js.map} +1 -1
- package/dist/{client-CKaAfPlF.d.cts → client-DKsEma11.d.cts} +580 -21
- package/dist/{client-CKaAfPlF.d.ts → client-DKsEma11.d.ts} +580 -21
- package/dist/index.cjs +307 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +272 -7
- package/dist/index.js.map +1 -1
- package/dist/solapi/index.cjs +7 -7
- package/dist/solapi/index.d.cts +2 -2
- package/dist/solapi/index.d.ts +2 -2
- package/dist/solapi/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-36JABW7P.js.map +0 -1
- 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.
|
|
720
|
+
console.log(`잘못된 요청: ${e.status} - ${JSON.stringify(e.body)}`);
|
|
650
721
|
} else if (e instanceof AuthenticationError) {
|
|
651
|
-
console.log(`유효하지 않은 API 키: ${e.
|
|
722
|
+
console.log(`유효하지 않은 API 키: ${e.status}`);
|
|
652
723
|
} else if (e instanceof NotFoundError) {
|
|
653
|
-
console.log(`리소스를 찾을 수 없음: ${e.
|
|
724
|
+
console.log(`리소스를 찾을 수 없음: ${e.status}`);
|
|
654
725
|
}
|
|
655
726
|
}
|
|
656
727
|
```
|
|
657
728
|
|
|
658
|
-
모든 에러는 `ClawOpsError`를 상속합니다. HTTP 에러는 `
|
|
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
|
| -------------------------- | --------- |
|
package/dist/agent/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkLKFNV2GI_cjs = require('../chunk-LKFNV2GI.cjs');
|
|
4
|
+
var chunkIYSPOOKH_cjs = require('../chunk-IYSPOOKH.cjs');
|
|
5
5
|
var chunkQD2ZY4UP_cjs = require('../chunk-QD2ZY4UP.cjs');
|
|
6
6
|
var fs = require('fs');
|
|
7
7
|
var path = require('path');
|
|
@@ -729,7 +729,7 @@ var MAX_ERROR_MESSAGE_LENGTH = 200;
|
|
|
729
729
|
function getSdkInfo() {
|
|
730
730
|
return {
|
|
731
731
|
name: "clawops-node",
|
|
732
|
-
version:
|
|
732
|
+
version: chunkLKFNV2GI_cjs.VERSION,
|
|
733
733
|
runtime: `node/${process.versions.node}`,
|
|
734
734
|
os: `${process.platform}/${os__default.default.arch()}`
|
|
735
735
|
};
|
|
@@ -1474,7 +1474,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1474
1474
|
constructor(options) {
|
|
1475
1475
|
this._apiKey = options.apiKey ?? process.env["CLAWOPS_API_KEY"] ?? "";
|
|
1476
1476
|
this._accountId = options.accountId ?? process.env["CLAWOPS_ACCOUNT_ID"] ?? "";
|
|
1477
|
-
this._baseUrl = options.baseUrl ??
|
|
1477
|
+
this._baseUrl = options.baseUrl ?? chunkLKFNV2GI_cjs.DEFAULT_BASE_URL;
|
|
1478
1478
|
this._fromNumber = options.from;
|
|
1479
1479
|
this._session = options.session;
|
|
1480
1480
|
this._recording = options.recording ?? false;
|
|
@@ -1498,7 +1498,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1498
1498
|
}
|
|
1499
1499
|
static _validateGain(name, gain) {
|
|
1500
1500
|
if (typeof gain !== "number" || !Number.isFinite(gain) || gain < 0) {
|
|
1501
|
-
throw new
|
|
1501
|
+
throw new chunkIYSPOOKH_cjs.AgentError(`${name}=${gain} must be a finite number >= 0`);
|
|
1502
1502
|
}
|
|
1503
1503
|
return gain;
|
|
1504
1504
|
}
|
|
@@ -1512,7 +1512,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1512
1512
|
tool(nameOrTool, description, parameters, handler) {
|
|
1513
1513
|
if (typeof nameOrTool === "string") {
|
|
1514
1514
|
if (!description || !parameters || !handler) {
|
|
1515
|
-
throw new
|
|
1515
|
+
throw new chunkIYSPOOKH_cjs.AgentError(
|
|
1516
1516
|
"tool(name, description, parameters, handler) requires all arguments."
|
|
1517
1517
|
);
|
|
1518
1518
|
}
|
|
@@ -1548,10 +1548,10 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1548
1548
|
async connect() {
|
|
1549
1549
|
if (this._controlWs) return;
|
|
1550
1550
|
if (!this._apiKey) {
|
|
1551
|
-
throw new
|
|
1551
|
+
throw new chunkIYSPOOKH_cjs.AgentError("API key is required. Set CLAWOPS_API_KEY or pass apiKey option.");
|
|
1552
1552
|
}
|
|
1553
1553
|
if (!this._accountId) {
|
|
1554
|
-
throw new
|
|
1554
|
+
throw new chunkIYSPOOKH_cjs.AgentError(
|
|
1555
1555
|
"Account ID is required. Set CLAWOPS_ACCOUNT_ID or pass accountId option."
|
|
1556
1556
|
);
|
|
1557
1557
|
}
|
|
@@ -1575,7 +1575,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1575
1575
|
} catch {
|
|
1576
1576
|
}
|
|
1577
1577
|
} catch (err) {
|
|
1578
|
-
throw new
|
|
1578
|
+
throw new chunkIYSPOOKH_cjs.AgentConnectionError(
|
|
1579
1579
|
`Failed to connect to ClawOps: ${err instanceof Error ? err.message : String(err)}`
|
|
1580
1580
|
);
|
|
1581
1581
|
}
|
|
@@ -1640,7 +1640,7 @@ var ClawOpsAgent = class _ClawOpsAgent {
|
|
|
1640
1640
|
});
|
|
1641
1641
|
if (resp.status !== 201) {
|
|
1642
1642
|
const error = await resp.json();
|
|
1643
|
-
throw new
|
|
1643
|
+
throw new chunkIYSPOOKH_cjs.AgentError(`\uBC1C\uC2E0 \uC2E4\uD328 (${resp.status}): ${error["error"] ?? ""}`);
|
|
1644
1644
|
}
|
|
1645
1645
|
const data = await resp.json();
|
|
1646
1646
|
const callSession = new CallSession({
|
package/dist/agent/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_BASE_URL, VERSION } from '../chunk-
|
|
2
|
-
import { AgentError, AgentConnectionError } from '../chunk-
|
|
1
|
+
import { DEFAULT_BASE_URL, VERSION } from '../chunk-XL2VWU36.js';
|
|
2
|
+
import { AgentError, AgentConnectionError } from '../chunk-VYGIWHRU.js';
|
|
3
3
|
import { NOOP_LOGGER, resolveBuiltinTools, createAgentLogger, createPipelineLogger, BufferingCall, attachBuffered, ulawToPcm16, resamplePcm16, getBuiltinToolSchemas, BUILTIN_TOOL_NAMES, executeBuiltinTool, CALL_NOT_READY_RESULT, pcm16ToUlaw, applyUlawGain } from '../chunk-4YLSDMLL.js';
|
|
4
4
|
export { BUILTIN_TOOL_NAMES, BuiltinTool, DECODE_TABLE, createAgentLogger, createPipelineLogger, executeBuiltinTool, getBuiltinToolSchemas, isBuiltinTool, pcm16ToUlaw, resamplePcm16, ulawToPcm16 } from '../chunk-4YLSDMLL.js';
|
|
5
5
|
import * as fs from 'fs';
|
|
@@ -19,14 +19,26 @@ var APIStatusError = class extends APIError {
|
|
|
19
19
|
status;
|
|
20
20
|
body;
|
|
21
21
|
headers;
|
|
22
|
+
/**
|
|
23
|
+
* 서버가 함께 보낸 기계 판독용 코드(`{ error, code }`). 없으면 undefined 다.
|
|
24
|
+
*
|
|
25
|
+
* 같은 상태 코드가 서로 다른 사유를 담는다 — 422 만 해도 수신거부(`recipient_blocked`)와
|
|
26
|
+
* 할당량 초과(`quota_exceeded`)가 갈리고, 한글 문구로 구분하면 문구가 바뀔 때 깨진다.
|
|
27
|
+
*/
|
|
28
|
+
code;
|
|
22
29
|
constructor(message, response, body, request) {
|
|
23
30
|
super(message, request);
|
|
24
31
|
this.name = "APIStatusError";
|
|
25
32
|
this.status = response.status;
|
|
26
33
|
this.body = body;
|
|
27
34
|
this.headers = response.headers;
|
|
35
|
+
this.code = extractErrorCode(body);
|
|
28
36
|
}
|
|
29
37
|
};
|
|
38
|
+
function extractErrorCode(body) {
|
|
39
|
+
const code = body?.code;
|
|
40
|
+
return typeof code === "string" && code !== "" ? code : void 0;
|
|
41
|
+
}
|
|
30
42
|
var BadRequestError = class extends APIStatusError {
|
|
31
43
|
status = 400;
|
|
32
44
|
constructor(message, response, body, request) {
|
|
@@ -175,5 +187,5 @@ exports.ServiceUnavailableError = ServiceUnavailableError;
|
|
|
175
187
|
exports.SolapiBridgeError = SolapiBridgeError;
|
|
176
188
|
exports.UnprocessableEntityError = UnprocessableEntityError;
|
|
177
189
|
exports.makeStatusError = makeStatusError;
|
|
178
|
-
//# sourceMappingURL=chunk-
|
|
179
|
-
//# sourceMappingURL=chunk-
|
|
190
|
+
//# sourceMappingURL=chunk-IYSPOOKH.cjs.map
|
|
191
|
+
//# sourceMappingURL=chunk-IYSPOOKH.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/error.ts"],"names":[],"mappings":"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","file":"chunk-IYSPOOKH.cjs","sourcesContent":["/**\n * 서버가 에러 응답의 `code` 로 싣는 값.\n *\n * 문구가 아니라 **이 값으로 분기한다** — 한글 메시지는 바뀔 수 있다.\n *\n * ⚠️ 문자 도메인은 snake_case, 카카오 채널 도메인은 SCREAMING_CASE 다. 서버가 실제로\n * 그렇게 보내므로 SDK 가 임의로 정규화하지 않는다. 열린 유니온이라 목록에 없는 코드도\n * 그대로 실린다(자동완성만 돕는다).\n */\nexport type ClawOpsErrorCode =\n // 발송 일반\n | 'invalid_phone'\n | 'invalid_type'\n | 'invalid_input'\n | 'from_not_registered'\n | 'body_too_long'\n | 'sms_no_subject'\n | 'sms_no_media'\n | 'lms_no_media'\n | 'too_many_media'\n | 'invalid_media_ext'\n | 'media_download_failed'\n | 'type_not_supported'\n | 'messaging_blocked'\n | 'recipient_blocked'\n | 'quota_exceeded'\n | 'override_quota_exceeded'\n | 'no_active_subscription'\n // 알림톡 발송\n | 'kakao_required'\n | 'kakao_type_conflict'\n | 'kakao_body_not_allowed'\n | 'kakao_subject_not_allowed'\n | 'kakao_media_not_allowed'\n | 'kakao_channel_not_found'\n | 'kakao_template_not_found'\n | 'kakao_template_not_approved'\n | 'kakao_template_dormant'\n | 'kakao_variable_missing'\n | 'kakao_variable_unknown'\n | 'kakao_send_failed'\n | 'kakao_unavailable'\n | 'invalid_fallback_type'\n // 카카오 채널 연동\n | 'KAKAO_TOKEN_INVALID'\n | 'KAKAO_CHANNEL_ALREADY_LINKED'\n | 'KAKAO_CHANNEL_REJECTED'\n | 'KAKAO_RATE_LIMITED'\n | 'KAKAO_PROVIDER_UNAVAILABLE'\n // 공통\n | 'VALIDATION'\n | 'NOT_FOUND'\n | (string & {});\n\nexport class ClawOpsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ClawOpsError';\n }\n}\n\nexport class APIError extends ClawOpsError {\n readonly request: { method: string; url: string };\n\n constructor(message: string, request: { method: string; url: string }) {\n super(message);\n this.name = 'APIError';\n this.request = request;\n }\n}\n\nexport class APIStatusError extends APIError {\n readonly status: number;\n readonly body: unknown;\n readonly headers: Headers | undefined;\n /**\n * 서버가 함께 보낸 기계 판독용 코드(`{ error, code }`). 없으면 undefined 다.\n *\n * 같은 상태 코드가 서로 다른 사유를 담는다 — 422 만 해도 수신거부(`recipient_blocked`)와\n * 할당량 초과(`quota_exceeded`)가 갈리고, 한글 문구로 구분하면 문구가 바뀔 때 깨진다.\n */\n readonly code: ClawOpsErrorCode | undefined;\n\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, request);\n this.name = 'APIStatusError';\n this.status = response.status;\n this.body = body;\n this.headers = response.headers;\n this.code = extractErrorCode(body);\n }\n}\n\n/** 응답 본문에서 `code` 를 꺼낸다. 문자열이 아니면 없는 것으로 본다. */\nfunction extractErrorCode(body: unknown): ClawOpsErrorCode | undefined {\n const code = (body as { code?: unknown } | null | undefined)?.code;\n return typeof code === 'string' && code !== '' ? code : undefined;\n}\n\nexport class BadRequestError extends APIStatusError {\n override readonly status = 400 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends APIStatusError {\n override readonly status = 401 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class PermissionDeniedError extends APIStatusError {\n override readonly status = 403 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'PermissionDeniedError';\n }\n}\n\nexport class NotFoundError extends APIStatusError {\n override readonly status = 404 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends APIStatusError {\n override readonly status = 409 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'ConflictError';\n }\n}\n\nexport class UnprocessableEntityError extends APIStatusError {\n override readonly status = 422 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'UnprocessableEntityError';\n }\n}\n\n/**\n * HTTP 429 Too Many Requests.\n *\n * 동시 통화 한도 초과 등 일시적 제한. SDK는 자동 재시도(최대 2회, 지수 backoff)를 수행한다.\n * 즉각 피드백이 필요하면 client 생성 시 maxRetries: 0으로 재시도를 비활성화하라.\n */\nexport class RateLimitError extends APIStatusError {\n override readonly status = 429 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'RateLimitError';\n }\n}\n\nexport class InternalServerError extends APIStatusError {\n override readonly status = 500 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'InternalServerError';\n }\n}\n\nexport class ServiceUnavailableError extends APIStatusError {\n override readonly status = 503 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'ServiceUnavailableError';\n }\n}\n\nexport class APIConnectionError extends APIError {\n constructor(request: { method: string; url: string }, message = 'Connection error.') {\n super(message, request);\n this.name = 'APIConnectionError';\n }\n}\n\nexport class APITimeoutError extends APIConnectionError {\n constructor(request: { method: string; url: string }) {\n super(request, 'Request timed out.');\n this.name = 'APITimeoutError';\n }\n}\n\nexport class APIResponseValidationError extends APIError {\n readonly status: number;\n\n constructor(response: { status: number }, request: { method: string; url: string }) {\n super('API response validation failed.', request);\n this.name = 'APIResponseValidationError';\n this.status = response.status;\n }\n}\n\n/**\n * 솔라피 호환 레이어가 호출을 거절할 때 쓴다.\n * 조용히 다르게 동작하느니 여기서 멈추는 편이 낫다고 판단한 경우들이다.\n */\nexport class SolapiBridgeError extends ClawOpsError {\n constructor(message: string) {\n super(message);\n this.name = 'SolapiBridgeError';\n }\n}\n\nexport class AgentError extends ClawOpsError {\n constructor(message: string) {\n super(message);\n this.name = 'AgentError';\n }\n}\n\nexport class AgentConnectionError extends AgentError {\n constructor(message = 'Agent WebSocket connection failed.') {\n super(message);\n this.name = 'AgentConnectionError';\n }\n}\n\nconst STATUS_CODE_TO_ERROR: Record<\n number,\n new (\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) => APIStatusError\n> = {\n 400: BadRequestError,\n 401: AuthenticationError,\n 403: PermissionDeniedError,\n 404: NotFoundError,\n 409: ConflictError,\n 422: UnprocessableEntityError,\n 429: RateLimitError,\n 500: InternalServerError,\n 503: ServiceUnavailableError,\n};\n\nexport function makeStatusError(\n status: number,\n body: unknown,\n headers: Headers | undefined,\n request: { method: string; url: string },\n): APIStatusError {\n let message = '';\n if (body && typeof body === 'object' && 'error' in body) {\n message = (body as { error: string }).error;\n } else {\n message = `HTTP ${status}`;\n }\n\n const ErrorClass = STATUS_CODE_TO_ERROR[status];\n if (ErrorClass) {\n return new ErrorClass(message, { status, headers }, body, request);\n }\n if (status >= 500) {\n return new InternalServerError(message, { status, headers }, body, request);\n }\n return new APIStatusError(message, { status, headers }, body, request);\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/version.ts
|
|
4
|
-
var VERSION = "0.
|
|
4
|
+
var VERSION = "0.36.0" ;
|
|
5
5
|
|
|
6
6
|
// src/constants.ts
|
|
7
7
|
var DEFAULT_BASE_URL = "https://api.claw-ops.com";
|
|
@@ -16,5 +16,5 @@ exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
|
|
|
16
16
|
exports.INITIAL_RETRY_DELAY = INITIAL_RETRY_DELAY;
|
|
17
17
|
exports.MAX_RETRY_DELAY = MAX_RETRY_DELAY;
|
|
18
18
|
exports.VERSION = VERSION;
|
|
19
|
-
//# sourceMappingURL=chunk-
|
|
20
|
-
//# sourceMappingURL=chunk-
|
|
19
|
+
//# sourceMappingURL=chunk-LKFNV2GI.cjs.map
|
|
20
|
+
//# sourceMappingURL=chunk-LKFNV2GI.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts","../src/constants.ts"],"names":[],"mappings":";;;AAEO,IAAM,OAAA,GACT,QAAA;;;ACHG,IAAM,gBAAA,GAAmB;AACzB,IAAM,mBAAA,GAAsB;AAC5B,IAAM,eAAA,GAAkB;AACxB,IAAM,mBAAA,GAAsB;AAC5B,IAAM,eAAA,GAAkB","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/version.ts","../src/constants.ts"],"names":[],"mappings":";;;AAEO,IAAM,OAAA,GACT,QAAA;;;ACHG,IAAM,gBAAA,GAAmB;AACzB,IAAM,mBAAA,GAAsB;AAC5B,IAAM,eAAA,GAAkB;AACxB,IAAM,mBAAA,GAAsB;AAC5B,IAAM,eAAA,GAAkB","file":"chunk-LKFNV2GI.cjs","sourcesContent":["declare const __PKG_VERSION__: string;\n\nexport const VERSION: string = typeof __PKG_VERSION__ !== 'undefined'\n ? __PKG_VERSION__\n : 'dev';\n","export const DEFAULT_BASE_URL = 'https://api.claw-ops.com';\nexport const DEFAULT_MAX_RETRIES = 2;\nexport const DEFAULT_TIMEOUT = 600_000; // ms\nexport const INITIAL_RETRY_DELAY = 500; // ms\nexport const MAX_RETRY_DELAY = 8_000; // ms\n"]}
|
|
@@ -17,14 +17,26 @@ var APIStatusError = class extends APIError {
|
|
|
17
17
|
status;
|
|
18
18
|
body;
|
|
19
19
|
headers;
|
|
20
|
+
/**
|
|
21
|
+
* 서버가 함께 보낸 기계 판독용 코드(`{ error, code }`). 없으면 undefined 다.
|
|
22
|
+
*
|
|
23
|
+
* 같은 상태 코드가 서로 다른 사유를 담는다 — 422 만 해도 수신거부(`recipient_blocked`)와
|
|
24
|
+
* 할당량 초과(`quota_exceeded`)가 갈리고, 한글 문구로 구분하면 문구가 바뀔 때 깨진다.
|
|
25
|
+
*/
|
|
26
|
+
code;
|
|
20
27
|
constructor(message, response, body, request) {
|
|
21
28
|
super(message, request);
|
|
22
29
|
this.name = "APIStatusError";
|
|
23
30
|
this.status = response.status;
|
|
24
31
|
this.body = body;
|
|
25
32
|
this.headers = response.headers;
|
|
33
|
+
this.code = extractErrorCode(body);
|
|
26
34
|
}
|
|
27
35
|
};
|
|
36
|
+
function extractErrorCode(body) {
|
|
37
|
+
const code = body?.code;
|
|
38
|
+
return typeof code === "string" && code !== "" ? code : void 0;
|
|
39
|
+
}
|
|
28
40
|
var BadRequestError = class extends APIStatusError {
|
|
29
41
|
status = 400;
|
|
30
42
|
constructor(message, response, body, request) {
|
|
@@ -155,5 +167,5 @@ function makeStatusError(status, body, headers, request) {
|
|
|
155
167
|
}
|
|
156
168
|
|
|
157
169
|
export { APIConnectionError, APIError, APIResponseValidationError, APIStatusError, APITimeoutError, AgentConnectionError, AgentError, AuthenticationError, BadRequestError, ClawOpsError, ConflictError, InternalServerError, NotFoundError, PermissionDeniedError, RateLimitError, ServiceUnavailableError, SolapiBridgeError, UnprocessableEntityError, makeStatusError };
|
|
158
|
-
//# sourceMappingURL=chunk-
|
|
159
|
-
//# sourceMappingURL=chunk-
|
|
170
|
+
//# sourceMappingURL=chunk-VYGIWHRU.js.map
|
|
171
|
+
//# sourceMappingURL=chunk-VYGIWHRU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/error.ts"],"names":[],"mappings":"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","file":"chunk-VYGIWHRU.js","sourcesContent":["/**\n * 서버가 에러 응답의 `code` 로 싣는 값.\n *\n * 문구가 아니라 **이 값으로 분기한다** — 한글 메시지는 바뀔 수 있다.\n *\n * ⚠️ 문자 도메인은 snake_case, 카카오 채널 도메인은 SCREAMING_CASE 다. 서버가 실제로\n * 그렇게 보내므로 SDK 가 임의로 정규화하지 않는다. 열린 유니온이라 목록에 없는 코드도\n * 그대로 실린다(자동완성만 돕는다).\n */\nexport type ClawOpsErrorCode =\n // 발송 일반\n | 'invalid_phone'\n | 'invalid_type'\n | 'invalid_input'\n | 'from_not_registered'\n | 'body_too_long'\n | 'sms_no_subject'\n | 'sms_no_media'\n | 'lms_no_media'\n | 'too_many_media'\n | 'invalid_media_ext'\n | 'media_download_failed'\n | 'type_not_supported'\n | 'messaging_blocked'\n | 'recipient_blocked'\n | 'quota_exceeded'\n | 'override_quota_exceeded'\n | 'no_active_subscription'\n // 알림톡 발송\n | 'kakao_required'\n | 'kakao_type_conflict'\n | 'kakao_body_not_allowed'\n | 'kakao_subject_not_allowed'\n | 'kakao_media_not_allowed'\n | 'kakao_channel_not_found'\n | 'kakao_template_not_found'\n | 'kakao_template_not_approved'\n | 'kakao_template_dormant'\n | 'kakao_variable_missing'\n | 'kakao_variable_unknown'\n | 'kakao_send_failed'\n | 'kakao_unavailable'\n | 'invalid_fallback_type'\n // 카카오 채널 연동\n | 'KAKAO_TOKEN_INVALID'\n | 'KAKAO_CHANNEL_ALREADY_LINKED'\n | 'KAKAO_CHANNEL_REJECTED'\n | 'KAKAO_RATE_LIMITED'\n | 'KAKAO_PROVIDER_UNAVAILABLE'\n // 공통\n | 'VALIDATION'\n | 'NOT_FOUND'\n | (string & {});\n\nexport class ClawOpsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ClawOpsError';\n }\n}\n\nexport class APIError extends ClawOpsError {\n readonly request: { method: string; url: string };\n\n constructor(message: string, request: { method: string; url: string }) {\n super(message);\n this.name = 'APIError';\n this.request = request;\n }\n}\n\nexport class APIStatusError extends APIError {\n readonly status: number;\n readonly body: unknown;\n readonly headers: Headers | undefined;\n /**\n * 서버가 함께 보낸 기계 판독용 코드(`{ error, code }`). 없으면 undefined 다.\n *\n * 같은 상태 코드가 서로 다른 사유를 담는다 — 422 만 해도 수신거부(`recipient_blocked`)와\n * 할당량 초과(`quota_exceeded`)가 갈리고, 한글 문구로 구분하면 문구가 바뀔 때 깨진다.\n */\n readonly code: ClawOpsErrorCode | undefined;\n\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, request);\n this.name = 'APIStatusError';\n this.status = response.status;\n this.body = body;\n this.headers = response.headers;\n this.code = extractErrorCode(body);\n }\n}\n\n/** 응답 본문에서 `code` 를 꺼낸다. 문자열이 아니면 없는 것으로 본다. */\nfunction extractErrorCode(body: unknown): ClawOpsErrorCode | undefined {\n const code = (body as { code?: unknown } | null | undefined)?.code;\n return typeof code === 'string' && code !== '' ? code : undefined;\n}\n\nexport class BadRequestError extends APIStatusError {\n override readonly status = 400 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends APIStatusError {\n override readonly status = 401 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class PermissionDeniedError extends APIStatusError {\n override readonly status = 403 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'PermissionDeniedError';\n }\n}\n\nexport class NotFoundError extends APIStatusError {\n override readonly status = 404 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends APIStatusError {\n override readonly status = 409 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'ConflictError';\n }\n}\n\nexport class UnprocessableEntityError extends APIStatusError {\n override readonly status = 422 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'UnprocessableEntityError';\n }\n}\n\n/**\n * HTTP 429 Too Many Requests.\n *\n * 동시 통화 한도 초과 등 일시적 제한. SDK는 자동 재시도(최대 2회, 지수 backoff)를 수행한다.\n * 즉각 피드백이 필요하면 client 생성 시 maxRetries: 0으로 재시도를 비활성화하라.\n */\nexport class RateLimitError extends APIStatusError {\n override readonly status = 429 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'RateLimitError';\n }\n}\n\nexport class InternalServerError extends APIStatusError {\n override readonly status = 500 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'InternalServerError';\n }\n}\n\nexport class ServiceUnavailableError extends APIStatusError {\n override readonly status = 503 as const;\n constructor(\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) {\n super(message, response, body, request);\n this.name = 'ServiceUnavailableError';\n }\n}\n\nexport class APIConnectionError extends APIError {\n constructor(request: { method: string; url: string }, message = 'Connection error.') {\n super(message, request);\n this.name = 'APIConnectionError';\n }\n}\n\nexport class APITimeoutError extends APIConnectionError {\n constructor(request: { method: string; url: string }) {\n super(request, 'Request timed out.');\n this.name = 'APITimeoutError';\n }\n}\n\nexport class APIResponseValidationError extends APIError {\n readonly status: number;\n\n constructor(response: { status: number }, request: { method: string; url: string }) {\n super('API response validation failed.', request);\n this.name = 'APIResponseValidationError';\n this.status = response.status;\n }\n}\n\n/**\n * 솔라피 호환 레이어가 호출을 거절할 때 쓴다.\n * 조용히 다르게 동작하느니 여기서 멈추는 편이 낫다고 판단한 경우들이다.\n */\nexport class SolapiBridgeError extends ClawOpsError {\n constructor(message: string) {\n super(message);\n this.name = 'SolapiBridgeError';\n }\n}\n\nexport class AgentError extends ClawOpsError {\n constructor(message: string) {\n super(message);\n this.name = 'AgentError';\n }\n}\n\nexport class AgentConnectionError extends AgentError {\n constructor(message = 'Agent WebSocket connection failed.') {\n super(message);\n this.name = 'AgentConnectionError';\n }\n}\n\nconst STATUS_CODE_TO_ERROR: Record<\n number,\n new (\n message: string,\n response: { status: number; headers?: Headers },\n body: unknown,\n request: { method: string; url: string },\n ) => APIStatusError\n> = {\n 400: BadRequestError,\n 401: AuthenticationError,\n 403: PermissionDeniedError,\n 404: NotFoundError,\n 409: ConflictError,\n 422: UnprocessableEntityError,\n 429: RateLimitError,\n 500: InternalServerError,\n 503: ServiceUnavailableError,\n};\n\nexport function makeStatusError(\n status: number,\n body: unknown,\n headers: Headers | undefined,\n request: { method: string; url: string },\n): APIStatusError {\n let message = '';\n if (body && typeof body === 'object' && 'error' in body) {\n message = (body as { error: string }).error;\n } else {\n message = `HTTP ${status}`;\n }\n\n const ErrorClass = STATUS_CODE_TO_ERROR[status];\n if (ErrorClass) {\n return new ErrorClass(message, { status, headers }, body, request);\n }\n if (status >= 500) {\n return new InternalServerError(message, { status, headers }, body, request);\n }\n return new APIStatusError(message, { status, headers }, body, request);\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var VERSION = "0.
|
|
2
|
+
var VERSION = "0.36.0" ;
|
|
3
3
|
|
|
4
4
|
// src/constants.ts
|
|
5
5
|
var DEFAULT_BASE_URL = "https://api.claw-ops.com";
|
|
@@ -9,5 +9,5 @@ var INITIAL_RETRY_DELAY = 500;
|
|
|
9
9
|
var MAX_RETRY_DELAY = 8e3;
|
|
10
10
|
|
|
11
11
|
export { DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, INITIAL_RETRY_DELAY, MAX_RETRY_DELAY, VERSION };
|
|
12
|
-
//# sourceMappingURL=chunk-
|
|
13
|
-
//# sourceMappingURL=chunk-
|
|
12
|
+
//# sourceMappingURL=chunk-XL2VWU36.js.map
|
|
13
|
+
//# sourceMappingURL=chunk-XL2VWU36.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts","../src/constants.ts"],"names":[],"mappings":";AAEO,IAAM,OAAA,GACT,QAAA;;;ACHG,IAAM,gBAAA,GAAmB;AACzB,IAAM,mBAAA,GAAsB;AAC5B,IAAM,eAAA,GAAkB;AACxB,IAAM,mBAAA,GAAsB;AAC5B,IAAM,eAAA,GAAkB","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/version.ts","../src/constants.ts"],"names":[],"mappings":";AAEO,IAAM,OAAA,GACT,QAAA;;;ACHG,IAAM,gBAAA,GAAmB;AACzB,IAAM,mBAAA,GAAsB;AAC5B,IAAM,eAAA,GAAkB;AACxB,IAAM,mBAAA,GAAsB;AAC5B,IAAM,eAAA,GAAkB","file":"chunk-XL2VWU36.js","sourcesContent":["declare const __PKG_VERSION__: string;\n\nexport const VERSION: string = typeof __PKG_VERSION__ !== 'undefined'\n ? __PKG_VERSION__\n : 'dev';\n","export const DEFAULT_BASE_URL = 'https://api.claw-ops.com';\nexport const DEFAULT_MAX_RETRIES = 2;\nexport const DEFAULT_TIMEOUT = 600_000; // ms\nexport const INITIAL_RETRY_DELAY = 500; // ms\nexport const MAX_RETRY_DELAY = 8_000; // ms\n"]}
|