@k-msg/provider
k-msg용 provider 구현 패키지입니다. (SendOptions + Result 기반)
npm install @k-msg/provider @k-msg/core# orbun add @k-msg/provider @k-msg/coreSOLAPI provider를 사용할 경우, 앱에서 최신 solapi를 별도로 설치하세요. @k-msg/provider는 현재 v6 라인과 이전 v5 peer 범위를 함께 지원합니다:
npm install solapi# orbun add solapi기본 제공 Provider
섹션 제목: “기본 제공 Provider”SolapiProvider(SOLAPI)IWINVProvider(IWINV 알림톡, SMS v2, RCS 템플릿 중 원하는 조합,src/iwinv/README_ko.md참고)AligoProvider(Aligo)MockProvider(벤더 API를 호출하지 않는 테스트·로컬 실행용).{ id }를 넘기면 인스턴스마다 provider id를 따로 줄 수 있어, 예를 들어 mock 두 개로routing.byType을 시험할 수 있습니다. 기본 id는"mock"입니다.
모든 provider는 @k-msg/core의 Provider 인터페이스를 구현합니다:
supportedTypes: 지원하는 메시지type선언send(options: SendOptions, context?: ProviderRequestContext):Result<SendResult, KMsgError>반환 (throw 하지 않음)- 일부 provider는 선택 capability인
getBalance(query?)를 함께 구현합니다.
호출 단위 transport context
섹션 제목: “호출 단위 transport context”ProviderRequestContext로 AbortSignal과 호출 단위 fetch 구현을 전달할
수 있습니다. 기능에 의존하기 전에 provider.transportCapabilities를
확인해야 하며, capability 선언이 없으면 unsupported로 취급합니다.
| Provider | AbortSignal | Injectable fetch | 비고 |
|---|---|---|---|
iwinv |
supported | supported | send와 getDeliveryStatus의 모든 내부 요청에 context 전달 |
aligo |
supported | supported | 모든 send 채널이 공통 fetch transport 사용 |
solapi |
supported | unsupported | SOLAPI SDK가 signal/fetch를 받지 않으므로 SDK 호출 전마다 signal을 확인하고, abort되면 기다리지 않고 반환합니다. SDK가 이미 보낸 발송 요청은 취소할 수 없어 SOLAPI가 그 메시지를 보낼 수 있으므로, 이 경우는 타임아웃이라도 REQUEST_ABORTED(기본적으로 재시도하지 않음)를 반환합니다 |
mock |
supported | unsupported | 모의 지연은 signal을 따르며 HTTP transport는 사용하지 않음 |
const controller = new AbortController();const result = await provider.send(input, { signal: controller.signal, fetch: globalThis.fetch,});import 경로:
@k-msg/provider: 런타임 중립 export (IWINVProvider,AligoProvider, 온보딩 헬퍼, mock)@k-msg/provider/aligo: Aligo provider export@k-msg/provider/solapi: SOLAPI provider export (solapi는 사용자 앱에서 직접 설치)
Provider 온보딩 매트릭스
섹션 제목: “Provider 온보딩 매트릭스”단일 소스: packages/provider/src/onboarding/specs.ts
| Provider | 채널 온보딩 | 템플릿 API | plusId 정책 | plusId 추론 | 라이브 테스트 지원 |
|---|---|---|---|---|---|
iwinv |
수동(콘솔) | 가능 | optional | unsupported | supported |
aligo |
API | 가능 | required_if_no_inference | supported | supported |
solapi |
없음(벤더 메타 의존) | 미지원 | optional | unsupported | partial |
mock |
API(테스트용) | 가능 | optional | supported | none |
런타임 접근:
- 각 built-in provider는
getOnboardingSpec()를 노출합니다. - 레지스트리 헬퍼:
getProviderOnboardingSpec,listProviderOnboardingSpecs,providerOnboardingSpecs.
해석 기준:
- 여기서의
채널 온보딩은 vendor prerequisite path(manual,api,none)를 뜻하며, toolkit이 관리하는 approval state를 의미하지 않습니다. - CLI가
onboarding.manualChecks를 저장하는 경우도 외부 벤더 절차에 대한 operator evidence/note를 기록하는 용도입니다.
ALIMTALK 템플릿 변수
섹션 제목: “ALIMTALK 템플릿 변수”variables는 템플릿의 #{이름} 변수에 이름으로 매칭됩니다:
| Provider | 전송 방식 |
|---|---|
iwinv |
templateParam, 서로 다른 변수 이름마다 값 하나를, 내용과 버튼 링크에서 처음 나오는 순서대로 |
aligo |
message_1, 값을 채운 템플릿 본문 |
solapi |
kakaoOptions.variables, 템플릿은 SOLAPI가 채움 |
IWINV와 Aligo는 이를 위해 템플릿 본문이 필요합니다. providerOptions.templateContent에서 읽고, 없으면 템플릿 API(IWINV POST /api/template/, Aligo /akv10/template/list/)를 발송과 같은 request context로 조회해 provider 인스턴스마다 10분간 재사용합니다. variables에 값이 없는 변수(키가 없거나 undefined)가 템플릿에 있으면 아무것도 보내지 않고 INVALID_REQUEST로 실패합니다. IWINV는 variables가 비어 있고 templateContent도 없으면 조회하지 않으며, providerOptions.templateParam은 그대로 보냅니다(src/iwinv/README_ko.md 참고).
전송 결과 조회
섹션 제목: “전송 결과 조회”@k-msg/messaging의 DeliveryTrackingService는 provider.getDeliveryStatus()를 폴링합니다.
| Provider | getDeliveryStatus |
|---|---|
iwinv |
알림톡 전송내역, SMS/LMS/MMS 전송내역은 smsCompanyId 필요, RCS 전송내역은 브랜드·템플릿·수신번호·요청 시각으로 매칭(IWINV 발송 응답에 메시지 키가 없음) |
solapi |
SOLAPI 메시지 목록 |
aligo |
미구현 |
Aligo에는 결과 조회 API(/akv10/history/detail/, /sms_list/)가 있지만 반환하는 결과 코드를 공개하지 않아 AligoProvider에는 getDeliveryStatus()가 없습니다. 추적 중인 Aligo 메시지는 polling.maxTrackingDurationMs(기본 24시간)가 지나 UNKNOWN이 될 때까지 SENT로 남습니다. 첫 폴링에서 바로 정리하려면 polling.unsupportedProviderStrategy: "unknown"을 설정하세요. 같은 이유로 tracking 기반 API failover는 Aligo 알림톡을 재발송하지 않으며, failover.enabled이면 Aligo가 대체문자를 직접 보냅니다.
ALIMTALK failover 책임 범위
섹션 제목: “ALIMTALK failover 책임 범위”ALIMTALK의 failover는 @k-msg/core에서 표준화되어 있지만 provider별 native 매핑은 다릅니다.
| Provider | Native mapping | Warning |
|---|---|---|
iwinv |
reSend, resendType, resendContent, resendTitle |
none (native로 처리) |
solapi |
kakao.disableSms, text, subject |
발신번호가 없을 때만 FAILOVER_PARTIAL_PROVIDER |
aligo |
failover, fmessage_1, fsubject_1 |
FAILOVER_PARTIAL_PROVIDER |
mock |
native 매핑 없음 | FAILOVER_UNSUPPORTED_PROVIDER |
경계:
- provider 패키지는 벤더 native 필드로 매핑하고 warning 메타데이터를 반환합니다.
iwinv는failover.fallbackContent를resendContent(resendType: "N")로 보내고, 없으면 IWINV가 알림톡 내용을 대체문자로 보냅니다. SMS/LMS는 내용 길이로 IWINV가 정합니다.- tracking 기반 API 레벨 fallback retry(배달 폴링 + SMS/LMS 재발송)는
@k-msg/messaging에서 처리하며, 위 warning을 반환한 발송에만 적용됩니다. solapi는 알림톡에 발신번호(from또는defaultFrom)가 있으면 대체문자를 직접 보내므로(kakao.disableSms: false) warning을 반환하지 않습니다. 발신번호가 없으면 SOLAPI가 대체발송할 수 없어 API 레벨 fallback 대상으로 표시됩니다.
RCS failover
섹션 제목: “RCS failover”RCS_TPL/RCS_ITPL/RCS_LTPL의 failover(@k-msg/core의 RcsFailoverOptions, ALIMTALK과 같은 모양)는 RCS 메시지가 전달되지 않을 때 SMS/LMS 대체 문자를 요청합니다. KMsg는 ALIMTALK과 같이 변수를 채우고 SMS/LMS 크기를 정합니다. tracking 기반 API 레벨 fallback은 RCS에 적용되지 않습니다.
| Provider | Native mapping | Warning |
|---|---|---|
iwinv |
reSend, resendType, resendContent, resendTitle (RCS_TPL만) |
none (native로 처리) |
solapi |
매핑하지 않음, SOLAPI 자체 대체발송은 rcs.disableSms를 따름 |
FAILOVER_UNSUPPORTED_PROVIDER |
사용 예시 (KMsg와 함께)
섹션 제목: “사용 예시 (KMsg와 함께)”import { KMsg } from "@k-msg/messaging";import { IWINVProvider } from "@k-msg/provider";import { SolapiProvider } from "@k-msg/provider/solapi";
const kmsg = new KMsg({ providers: [ new SolapiProvider({ apiKey: process.env.SOLAPI_API_KEY!, apiSecret: process.env.SOLAPI_API_SECRET!, defaultFrom: "01000000000", }), new IWINVProvider({ apiKey: process.env.IWINV_API_KEY!, smsApiKey: process.env.IWINV_SMS_API_KEY, smsAuthKey: process.env.IWINV_SMS_AUTH_KEY, smsSenderNumber: "01000000000", }), ], routing: { defaultProviderId: "solapi", byType: { ALIMTALK: "iwinv" }, },});
await kmsg.send({ to: "01012345678", text: "hello" });Provider README 템플릿
섹션 제목: “Provider README 템플릿”새 provider를 추가할 때는 packages/provider/PROVIDER_README_TEMPLATE.md를 시작점으로 사용하고, 벤더 공식 문서 링크를 포함하세요.
Provider 구현 구조 가이드
섹션 제목: “Provider 구현 구조 가이드”provider 코드 구조 표준(파사드 + 도메인 모듈 + shared 유틸 승격 기준)은 아래 문서를 참고하세요.
packages/provider/src/PROVIDER_STRUCTURE.md