@k-msg/provider 0.25.1 → 0.27.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.
@@ -1,4 +1,4 @@
1
- var{defineProperty:j,getOwnPropertyNames:le,getOwnPropertyDescriptor:ce}=Object,fe=Object.prototype.hasOwnProperty;var Z=new WeakMap,ye=(e)=>{var t=Z.get(e),n;if(t)return t;if(t=j({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")le(e).map((r)=>!fe.call(t,r)&&j(t,r,{get:()=>e[r],enumerable:!(n=ce(e,r))||n.enumerable}));return Z.set(e,t),t};var ue=(e,t)=>{for(var n in t)j(e,n,{get:t[n],enumerable:!0,configurable:!0,set:(r)=>t[n]=()=>r})};var Ce={};ue(Ce,{initializeSolapi:()=>ae,createSolapiProvider:()=>$,createDefaultSolapiProvider:()=>H,SolapiProviderFactory:()=>G,SolapiProvider:()=>D});module.exports=ye(Ce);var ge={["INVALID_REQUEST"]:{ko:"잘못된 요청입니다",en:"Invalid request"},["AUTHENTICATION_FAILED"]:{ko:"인증에 실패했습니다",en:"Authentication failed"},["INSUFFICIENT_BALANCE"]:{ko:"잔액이 부족합니다",en:"Insufficient balance"},["TEMPLATE_NOT_FOUND"]:{ko:"템플릿을 찾을 수 없습니다",en:"Template not found"},["RATE_LIMIT_EXCEEDED"]:{ko:"요청 한도를 초과했습니다",en:"Rate limit exceeded"},["NETWORK_ERROR"]:{ko:"네트워크 오류가 발생했습니다",en:"Network error"},["NETWORK_TIMEOUT"]:{ko:"네트워크 요청 시간이 초과되었습니다",en:"Network timeout"},["NETWORK_SERVICE_UNAVAILABLE"]:{ko:"서비스를 일시적으로 사용할 수 없습니다",en:"Service temporarily unavailable"},["PROVIDER_ERROR"]:{ko:"제공자 오류가 발생했습니다",en:"Provider error"},["MESSAGE_SEND_FAILED"]:{ko:"메시지 전송에 실패했습니다",en:"Message send failed"},["CRYPTO_CONFIG_ERROR"]:{ko:"암호화 설정 오류가 발생했습니다",en:"Crypto configuration error"},["CRYPTO_ENCRYPT_FAILED"]:{ko:"암호화에 실패했습니다",en:"Encryption failed"},["CRYPTO_DECRYPT_FAILED"]:{ko:"복호화에 실패했습니다",en:"Decryption failed"},["CRYPTO_HASH_FAILED"]:{ko:"해시 생성에 실패했습니다",en:"Hash generation failed"},["CRYPTO_POLICY_VIOLATION"]:{ko:"암호화 정책 위반이 발생했습니다",en:"Crypto policy violation"},["UNKNOWN_ERROR"]:{ko:"알 수 없는 오류가 발생했습니다",en:"Unknown error"}};var Q=(e)=>{if(typeof e!=="number"||Number.isNaN(e)||!Number.isFinite(e))return;return Math.trunc(e)};class a extends Error{code;details;providerErrorCode;providerErrorText;httpStatus;requestId;retryAfterMs;attempt;causeChain;constructor(e,t,n,r={}){super(t);if(this.name="KMsgError",this.code=e,this.details=n,this.providerErrorCode=r.providerErrorCode,this.providerErrorText=r.providerErrorText,this.httpStatus=Q(r.httpStatus),this.requestId=typeof r.requestId==="string"?r.requestId:void 0,this.retryAfterMs=Q(r.retryAfterMs),this.attempt=Q(r.attempt),Array.isArray(r.causeChain))this.causeChain=r.causeChain;else if(r.causeChain!==void 0)this.causeChain=[r.causeChain];if(Error.captureStackTrace)Error.captureStackTrace(this,a)}getLocalizedMessage(e="ko"){let t=ge[this.code];if(t?.[e])return t[e];return this.message}toJSON(){return{name:this.name,code:this.code,message:this.message,details:this.details,providerErrorCode:this.providerErrorCode,providerErrorText:this.providerErrorText,httpStatus:this.httpStatus,requestId:this.requestId,retryAfterMs:this.retryAfterMs,attempt:this.attempt,causeChain:this.causeChain}}}var A=(e)=>({isSuccess:!0,isFailure:!1,value:e}),w=(e)=>({isSuccess:!1,isFailure:!0,error:e});function Se(){let e=globalThis;return e.__K_MSG_ENV__??e.__ENV__??e.process?.env??{}}function b(e){let t=Se()[e];if(typeof t==="string")return t;if(t===void 0)return;return String(t)}var se=require("solapi");var z={iwinv:{providerId:"iwinv",providerName:"IWINV Messaging Provider",channelOnboarding:"manual",templateLifecycleApi:"available",plusIdPolicy:"optional",plusIdInference:"unsupported",liveTestSupport:"supported",checks:[{id:"channel_registered_in_console",title:"Kakao channel is registered in IWINV console",description:"IWINV channel onboarding is manual. Confirm channel registration and approval in console.",kind:"manual",severity:"blocker",scopes:["doctor","preflight"]},{id:"iwinv_config_required",title:"IWINV config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey"]},{id:"template_capability_available",title:"Template lifecycle APIs are available",kind:"capability",severity:"warning",scopes:["doctor","preflight"],capabilityMethods:["listTemplates","getTemplate","createTemplate","updateTemplate","deleteTemplate"]},{id:"template_list_probe",title:"Template list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_templates"}],notes:["Channel add/auth is not available via IWINV public API in current integration.","Template APIs are available and can be probed."]},aligo:{providerId:"aligo",providerName:"Aligo Smart SMS",channelOnboarding:"api",templateLifecycleApi:"available",plusIdPolicy:"required_if_no_inference",plusIdInference:"supported",liveTestSupport:"supported",checks:[{id:"aligo_config_required",title:"Aligo config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey","userId"]},{id:"channel_api_capability_available",title:"Kakao channel APIs are available",kind:"capability",severity:"warning",scopes:["doctor","preflight"],capabilityMethods:["listKakaoChannels","requestKakaoChannelAuth","addKakaoChannel"]},{id:"channel_list_probe",title:"Kakao channel list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_kakao_channels"},{id:"template_list_probe",title:"Template list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_templates"}]},solapi:{providerId:"solapi",providerName:"SOLAPI Messaging Provider",channelOnboarding:"none",templateLifecycleApi:"unavailable",plusIdPolicy:"required_if_no_inference",plusIdInference:"unsupported",liveTestSupport:"partial",checks:[{id:"solapi_config_required",title:"SOLAPI config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey","apiSecret"]}],notes:["SOLAPI ALIMTALK requires kakao profileId/pfId, but plusId inference is not available in current integration."]},mock:{providerId:"mock",providerName:"Mock Provider",channelOnboarding:"api",templateLifecycleApi:"available",plusIdPolicy:"optional",plusIdInference:"supported",liveTestSupport:"none",checks:[{id:"mock_template_capability_available",title:"Mock template APIs are available",kind:"capability",severity:"info",scopes:["doctor","preflight"],capabilityMethods:["listTemplates","getTemplate","createTemplate"]}]}};function ee(e){return z[e]}function Tt(){return Object.values(z)}function m(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}var S=require("solapi");function M(e,t){if(e instanceof a)return e;let n=m(e)?e:{};if(e instanceof S.ApiKeyError)return new a("AUTHENTICATION_FAILED",e.message,{providerId:t});if(e instanceof S.BadRequestError)return new a("INVALID_REQUEST",e.message,{providerId:t,validationErrors:n.validationErrors});if(e instanceof S.NetworkError)return new a("NETWORK_ERROR",e.message,{providerId:t,url:typeof n.url==="string"?n.url:void 0,method:typeof n.method==="string"?n.method:void 0,isRetryable:typeof n.isRetryable==="boolean"?n.isRetryable:!0});if(e instanceof S.ClientError){let r=typeof n.httpStatus==="number"?n.httpStatus:void 0,l=typeof r==="number"&&r>=400&&r<500;return new a(l?"INVALID_REQUEST":"PROVIDER_ERROR",e.message,{providerId:t,httpStatus:r,errorCode:n.errorCode,errorMessage:n.errorMessage,url:n.url})}if(e instanceof S.ServerError)return new a("PROVIDER_ERROR",e.message,{providerId:t,httpStatus:typeof n.httpStatus==="number"?n.httpStatus:void 0});if(e instanceof S.DefaultError)return new a("PROVIDER_ERROR",e.message,{providerId:t,errorCode:n.errorCode,errorMessage:n.errorMessage});return new a("UNKNOWN_ERROR",e instanceof Error?e.message:String(e),{providerId:t})}function te(e){if(!e)return"UNKNOWN";if(e==="2000")return"PENDING";if(e==="3000")return"SENT";if(e==="4000")return"DELIVERED";if(/^[123]\\d{3}$/.test(e))return"FAILED";return"UNKNOWN"}function W(e){if(typeof e!=="string"||e.trim().length===0)return;let t=new Date(e);if(Number.isNaN(t.getTime()))return;return t}function U(e){let t=e.trim();if(t.startsWith("+"))return`+${t.slice(1).replace(/\\D/g,"")}`;return t.replace(/\\D/g,"")}function O(e){let t={};if(!e)return t;for(let[n,r]of Object.entries(e)){if(r===void 0)continue;t[n]=r===null?"":r instanceof Date?r.toISOString():typeof r==="string"?r:String(r)}return t}function ne(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e){if(!n)continue;if(n.type!=="WL")continue;if(!n.name||!n.urlMobile)continue;t.push({buttonName:n.name,buttonType:"WL",linkMo:n.urlMobile,linkPc:n.urlPc})}return t.length>0?t:void 0}function q(e){let t=typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0?e.imageUrl.trim():void 0;if(t)return t;let n=e.media?.image;if(!n)return;if("ref"in n){let r=n.ref.trim();return r.length>0?r:void 0}throw new a("INVALID_REQUEST","SOLAPI image upload requires `options.imageUrl` or `options.media.image.ref` (url/path).",{providerId:e.providerId})}function _(e){return m(e)&&typeof e.fileId==="string"?e.fileId:void 0}function ie(e){switch(e.type){case"ALIMTALK":return"ATA";case"FRIENDTALK":return typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0||Boolean(e.media?.image)?"CTI":"CTA";default:return e.type}}async function re(e){let{providerId:t,client:n,query:r}=e,l=r.providerMessageId.trim();if(!l)return w(new a("INVALID_REQUEST","providerMessageId is required",{providerId:t}));try{let o=await n.getMessages({messageId:l,limit:1}),h=(m(o)?o:{}).messageList;if(!h||typeof h!=="object"||Array.isArray(h))return A(null);let p=h,F=p[l],B=Object.values(p).find((v)=>{if(!m(v))return!1;let E=v.messageId;return typeof E==="string"?E===l:!1}),k=m(F)?F:m(B)?B:void 0;if(!k)return A(null);let u=typeof k.statusCode==="string"?k.statusCode:void 0,P=te(u),C=W(k.dateSent),R=W(k.dateCompleted);return A({providerId:t,providerMessageId:l,status:P,statusCode:u,statusMessage:typeof k.statusMessage==="string"?k.statusMessage:void 0,sentAt:C,deliveredAt:R,raw:k})}catch(o){return w(M(o,t))}}function ke(e,t){if(e.type!=="ALIMTALK")return;if(e.failover?.enabled!==!0)return;return[{code:"FAILOVER_PARTIAL_PROVIDER",message:"SOLAPI failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.",details:{providerId:t,mappedFields:["kakao.disableSms","text","subject"],unsupportedFields:["fallbackChannel"]}}]}function be(e){let{options:t,response:n,providerId:r,warnings:l}=e,o=m(n)?n:{},I=typeof o.messageId==="string"?o.messageId:void 0;return{messageId:t.messageId||crypto.randomUUID(),providerId:r,providerMessageId:I,status:"SENT",type:t.type,to:t.to,...Array.isArray(l)&&l.length>0?{warnings:l}:{},raw:n}}async function Ie(e){let{options:t,providerId:n,config:r,client:l}=e,o=ie(t),I=t.options?.scheduledAt,h=typeof t.from==="string"&&t.from.length>0?t.from:r.defaultFrom,p={to:U(t.to),type:o},F=typeof t.options?.country==="string"&&t.options.country.length>0?t.options.country:typeof r.defaultCountry==="string"?r.defaultCountry:void 0;if(F)p.country=F;let N=t.options?.customFields;if(N&&typeof N==="object"){let i={};for(let[s,d]of Object.entries(N)){if(d===void 0)continue;i[s]=typeof d==="string"?d:String(d)}if(Object.keys(i).length>0)p.customFields=i}if(I)p.scheduledDate=I;if(o==="SMS"||o==="LMS"||o==="MMS"||o==="VOICE"||o==="FAX"||String(o).startsWith("RCS_")){if(!h||h.length===0)throw new a("INVALID_REQUEST","from is required (options.from or config.defaultFrom)",{providerId:n,type:t.type});p.from=U(h)}else if(h)p.from=U(h);if(o==="SMS"||o==="LMS"||o==="MMS"){let i=t,s=i.text;if(s.length===0)throw new a("INVALID_REQUEST","text is required for SMS/LMS/MMS",{providerId:n,type:t.type});p.text=s;let d=i.subject;if(d)p.subject=d;if(o==="MMS"){let c=q({imageUrl:i.imageUrl,media:i.media,providerId:n});if(!c)throw new a("INVALID_REQUEST","image is required for MMS (options.imageUrl or options.media.image.ref)",{providerId:n});let f=await l.uploadFile(c,"MMS"),y=_(f);if(typeof y==="string"&&y.length>0)p.imageId=y;else throw new a("PROVIDER_ERROR","Failed to upload MMS image",{providerId:n})}return p}if(o==="ATA"){let i=t,s=i.failover,d=typeof i.kakao?.profileId==="string"&&i.kakao.profileId.length>0?i.kakao.profileId:r.kakaoPfId;if(!d||d.length===0)throw new a("INVALID_REQUEST","kakao profileId is required (options.kakao.profileId or config.kakaoPfId)",{providerId:n});let c=typeof s?.fallbackContent==="string"&&s.fallbackContent.trim().length>0?s.fallbackContent.trim():void 0,f=typeof s?.fallbackTitle==="string"&&s.fallbackTitle.trim().length>0?s.fallbackTitle.trim():void 0,y=s?.enabled===!0?!1:s?.enabled===!1?!0:i.kakao?.disableSms;if(c)p.text=c;if(f)p.subject=f;return p.kakaoOptions={pfId:d,templateId:i.templateId,variables:O(i.variables),disableSms:y,adFlag:i.kakao?.adFlag,buttons:Array.isArray(i.kakao?.buttons)?i.kakao.buttons:void 0,imageId:i.kakao?.imageId},p}if(o==="CTA"||o==="CTI"){let i=t,s=i.text;if(s.length===0)throw new a("INVALID_REQUEST","text is required for FRIENDTALK",{providerId:n});let d=typeof i.kakao?.profileId==="string"&&i.kakao.profileId.length>0?i.kakao.profileId:r.kakaoPfId;if(!d||d.length===0)throw new a("INVALID_REQUEST","kakao profileId is required (options.kakao.profileId or config.kakaoPfId)",{providerId:n});let c=ne(i.buttons),f=Array.isArray(i.kakao?.buttons)?i.kakao.buttons:c,y=typeof i.kakao?.imageLink==="string"&&i.kakao.imageLink.length>0?i.kakao.imageLink:void 0,T=Array.isArray(f)&&f.length>0?f[0]:void 0,x=m(T)&&typeof T.linkMo==="string"?T.linkMo:void 0,J=y??x,Y;if(o==="CTI"){let X=q({imageUrl:i.imageUrl,media:i.media,providerId:n});if(!X)throw new a("INVALID_REQUEST","image is required for CTI (friendtalk image) (options.imageUrl or options.media.image.ref)",{providerId:n});if(!J)throw new a("INVALID_REQUEST","imageLink is required for friendtalk image upload (options.kakao.imageLink or WL button)",{providerId:n});let de=await l.uploadFile(X,"KAKAO",void 0,J),V=_(de);if(typeof V==="string"&&V.length>0)Y=V;else throw new a("PROVIDER_ERROR","Failed to upload friendtalk image",{providerId:n})}return p.text=s,p.kakaoOptions={pfId:d,variables:O(i.variables),disableSms:i.kakao?.disableSms,adFlag:i.kakao?.adFlag,buttons:f,imageId:Y},p}if(o==="NSA"){let i=t,s=typeof i.naver?.talkId==="string"&&i.naver.talkId.length>0?i.naver.talkId:r.naverTalkId;if(!s||s.length===0)throw new a("INVALID_REQUEST","naver talkId is required (options.naver.talkId or config.naverTalkId)",{providerId:n});let d=typeof i.naver?.templateId==="string"&&i.naver.templateId.length>0?i.naver.templateId:i.templateId,c={...O(i.variables),...O(i.naver?.variables)};return p.naverOptions={talkId:s,templateId:d,variables:c,disableSms:i.naver?.disableSms,buttons:Array.isArray(i.naver?.buttons)?i.naver.buttons:void 0},p}if(o==="VOICE"){let i=t,s=i.text;if(s.length===0)throw new a("INVALID_REQUEST","text is required for VOICE",{providerId:n});let d=i.voice?.voiceType,c=d==="FEMALE"||d==="MALE"?d:"FEMALE";return p.text=s,p.voiceOptions=i.voice?{...i.voice,voiceType:c}:{voiceType:c},p}if(o==="FAX"){let s=t.fax,c=Array.isArray(s?.fileIds)?s.fileIds.filter((f)=>typeof f==="string"&&f.length>0):[];if(c.length===0){let f=Array.isArray(s?.fileUrls)?s.fileUrls.filter((y)=>typeof y==="string"&&y.length>0):[];if(f.length===0)throw new a("INVALID_REQUEST","fax.fileIds or fax.fileUrls is required",{providerId:n});c=[];for(let y of f){let T=await l.uploadFile(y,"FAX"),x=_(T);if(typeof x==="string"&&x.length>0)c.push(x)}}if(c.length===0)throw new a("PROVIDER_ERROR","Failed to resolve fax fileIds",{providerId:n});return p.faxOptions={fileIds:c},p}let k=t,u=k.rcs,P=typeof u?.brandId==="string"&&u.brandId.length>0?u.brandId:r.rcsBrandId;if(!P||P.length===0)throw new a("INVALID_REQUEST","rcs brandId is required (options.rcs.brandId or config.rcsBrandId)",{providerId:n});let C={brandId:P,buttons:Array.isArray(u?.buttons)?u.buttons:void 0,copyAllowed:u?.copyAllowed,mmsType:u?.mmsType,commercialType:u?.commercialType,disableSms:u?.disableSms,variables:{...O(k.variables),...O(u?.variables)}};if(o==="RCS_TPL"||o==="RCS_ITPL"||o==="RCS_LTPL"){let i=t;C.templateId=typeof i.rcs?.templateId==="string"&&i.rcs.templateId.length>0?i.rcs.templateId:i.templateId}let R,v;if(o==="RCS_SMS"||o==="RCS_LMS"||o==="RCS_MMS"){let i=t;if(R=i.text,v=i.subject,!R||R.length===0)throw new a("INVALID_REQUEST","text is required for RCS text types",{providerId:n});if(p.text=R,v)p.subject=v}let E=u?.additionalBody,g=m(E)?E:void 0,pe=g&&typeof g.imageId==="string"&&g.imageId.length>0?g.imageId:g&&typeof g.imaggeId==="string"&&g.imaggeId.length>0?g.imaggeId:void 0,L=(i)=>{let s=g?{...g}:{},d=typeof s.title==="string"&&s.title.length>0?s.title:v||"RCS",c=typeof s.description==="string"&&s.description.length>0?s.description:R||"",f=pe??i,y={...s,title:d,description:c};if(typeof f==="string"&&f.length>0)y.imaggeId=f;return y};if(o==="RCS_MMS"){let i=t,s=q({imageUrl:i.imageUrl,media:i.media,providerId:n});if(s){let d=await l.uploadFile(s,"RCS"),c=_(d);if(typeof c==="string"&&c.length>0)C.additionalBody=L(c);else if(g)C.additionalBody=L(void 0)}else if(g)C.additionalBody=L(void 0)}else if(g)C.additionalBody=L(void 0);return p.rcsOptions=C,p}async function oe(e){let{providerId:t,client:n,config:r,options:l}=e,o=ke(l,t),I=await Ie({options:l,providerId:t,config:r,client:n}),h=await n.sendOne(I,r.appId);return A(be({options:l,response:h,providerId:t,warnings:o}))}class D{id="solapi";name="SOLAPI Messaging Provider";supportedTypes=["ALIMTALK","FRIENDTALK","SMS","LMS","MMS","NSA","VOICE","FAX","RCS_SMS","RCS_LMS","RCS_MMS","RCS_TPL","RCS_ITPL","RCS_LTPL"];config;client;getOnboardingSpec(){let e=ee(this.id);if(!e)throw new a("INVALID_REQUEST",`Onboarding spec missing for provider: ${this.id}`,{providerId:this.id});return e}constructor(e,t){if(!e||typeof e!=="object")throw new a("INVALID_REQUEST","SolapiProvider requires a config object",{providerId:this.id});if(!e.apiKey||e.apiKey.length===0)throw Error("SolapiProvider requires `apiKey`");if(!e.apiSecret||e.apiSecret.length===0)throw Error("SolapiProvider requires `apiSecret`");this.config={...e,baseUrl:typeof e.baseUrl==="string"&&e.baseUrl.length>0?e.baseUrl:"https://api.solapi.com"},this.client=t??new se.SolapiMessageService(this.config.apiKey,this.config.apiSecret)}async healthCheck(){let e=[],t=Date.now();try{if(!this.config.apiKey)e.push("Missing apiKey");if(!this.config.apiSecret)e.push("Missing apiSecret");if(this.config.baseUrl)try{new URL(this.config.baseUrl)}catch{e.push("Invalid baseUrl")}return{healthy:e.length===0,issues:e,latencyMs:Date.now()-t,data:{provider:this.id,baseUrl:this.config.baseUrl}}}catch(n){return e.push(n instanceof Error?n.message:String(n)),{healthy:!1,issues:e,latencyMs:Date.now()-t}}}async send(e){let t=e.messageId||crypto.randomUUID(),n={...e,messageId:t};try{return await oe({providerId:this.id,client:this.client,config:this.config,options:n})}catch(r){return w(M(r,this.id))}}async getDeliveryStatus(e){return re({providerId:this.id,client:this.client,query:e})}async getBalance(e){try{let t=await this.client.getBalance(),n=t,r=[n.balance,n.point],l=Number.NaN;for(let o of r){if(typeof o==="number"&&Number.isFinite(o)){l=o;break}if(typeof o==="string"){let I=Number(o);if(Number.isFinite(I)){l=I;break}}}if(!Number.isFinite(l))return w(M(Error("Invalid balance response from SOLAPI"),this.id));return A({providerId:this.id,channel:e?.channel,amount:l,currency:"KRW",raw:t})}catch(t){return w(M(t,this.id))}}}var $=(e)=>new D(e),H=()=>{let e={apiKey:b("SOLAPI_API_KEY")||"",apiSecret:b("SOLAPI_API_SECRET")||"",baseUrl:b("SOLAPI_BASE_URL")||"https://api.solapi.com",defaultFrom:b("SOLAPI_DEFAULT_FROM"),kakaoPfId:b("SOLAPI_KAKAO_PF_ID"),rcsBrandId:b("SOLAPI_RCS_BRAND_ID"),naverTalkId:b("SOLAPI_NAVER_TALK_ID"),appId:b("SOLAPI_APP_ID"),defaultCountry:b("SOLAPI_DEFAULT_COUNTRY"),debug:b("NODE_ENV")==="development"};if(!e.apiKey||!e.apiSecret)throw Error("SOLAPI_API_KEY and SOLAPI_API_SECRET environment variables are required");return $(e)};class G{static create(e){return new D(e)}static createDefault(){return H()}}function ae(){}
1
+ var{defineProperty:j,getOwnPropertyNames:de,getOwnPropertyDescriptor:pe}=Object,fe=Object.prototype.hasOwnProperty;var J=new WeakMap,ce=(e)=>{var t=J.get(e),n;if(t)return t;if(t=j({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")de(e).map((r)=>!fe.call(t,r)&&j(t,r,{get:()=>e[r],enumerable:!(n=pe(e,r))||n.enumerable}));return J.set(e,t),t};var ue=(e,t)=>{for(var n in t)j(e,n,{get:t[n],enumerable:!0,configurable:!0,set:(r)=>t[n]=()=>r})};var ye={};ue(ye,{initializeSolapi:()=>ae,createSolapiProvider:()=>W,createDefaultSolapiProvider:()=>X,SolapiProviderFactory:()=>z,SolapiProvider:()=>N});module.exports=ce(ye);var c=require("@k-msg/core"),oe=require("solapi");var Y={iwinv:{providerId:"iwinv",providerName:"IWINV Messaging Provider",channelOnboarding:"manual",templateLifecycleApi:"available",plusIdPolicy:"optional",plusIdInference:"unsupported",liveTestSupport:"supported",checks:[{id:"channel_registered_in_console",title:"Kakao channel is registered in IWINV console",description:"IWINV channel onboarding is manual. Confirm channel registration and approval in console.",kind:"manual",severity:"blocker",scopes:["doctor","preflight"]},{id:"iwinv_config_required",title:"IWINV config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey"]},{id:"template_capability_available",title:"Template lifecycle APIs are available",kind:"capability",severity:"warning",scopes:["doctor","preflight"],capabilityMethods:["listTemplates","getTemplate","createTemplate","updateTemplate","deleteTemplate"]},{id:"template_list_probe",title:"Template list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_templates"}],notes:["Channel add/auth is not available via IWINV public API in current integration.","Template APIs are available and can be probed."]},aligo:{providerId:"aligo",providerName:"Aligo Smart SMS",channelOnboarding:"api",templateLifecycleApi:"available",plusIdPolicy:"required_if_no_inference",plusIdInference:"supported",liveTestSupport:"supported",checks:[{id:"aligo_config_required",title:"Aligo config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey","userId"]},{id:"channel_api_capability_available",title:"Kakao channel APIs are available",kind:"capability",severity:"warning",scopes:["doctor","preflight"],capabilityMethods:["listKakaoChannels","requestKakaoChannelAuth","addKakaoChannel"]},{id:"channel_list_probe",title:"Kakao channel list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_kakao_channels"},{id:"template_list_probe",title:"Template list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_templates"}]},solapi:{providerId:"solapi",providerName:"SOLAPI Messaging Provider",channelOnboarding:"none",templateLifecycleApi:"unavailable",plusIdPolicy:"required_if_no_inference",plusIdInference:"unsupported",liveTestSupport:"partial",checks:[{id:"solapi_config_required",title:"SOLAPI config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey","apiSecret"]}],notes:["SOLAPI ALIMTALK requires kakao profileId/pfId, but plusId inference is not available in current integration."]},mock:{providerId:"mock",providerName:"Mock Provider",channelOnboarding:"api",templateLifecycleApi:"available",plusIdPolicy:"optional",plusIdInference:"supported",liveTestSupport:"none",checks:[{id:"mock_template_capability_available",title:"Mock template APIs are available",kind:"capability",severity:"info",scopes:["doctor","preflight"],capabilityMethods:["listTemplates","getTemplate","createTemplate"]}]}};function Z(e){return Y[e]}function ke(){return Object.values(Y)}var R=require("@k-msg/core");function S(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}var g=require("@k-msg/core"),b=require("solapi");function T(e,t){if(e instanceof g.KMsgError)return e;let n=S(e)?e:{};if(e instanceof b.ApiKeyError)return new g.KMsgError(g.KMsgErrorCode.AUTHENTICATION_FAILED,e.message,{providerId:t});if(e instanceof b.BadRequestError)return new g.KMsgError(g.KMsgErrorCode.INVALID_REQUEST,e.message,{providerId:t,validationErrors:n.validationErrors});if(e instanceof b.NetworkError)return new g.KMsgError(g.KMsgErrorCode.NETWORK_ERROR,e.message,{providerId:t,url:typeof n.url==="string"?n.url:void 0,method:typeof n.method==="string"?n.method:void 0,isRetryable:typeof n.isRetryable==="boolean"?n.isRetryable:!0});if(e instanceof b.ClientError){let r=typeof n.httpStatus==="number"?n.httpStatus:void 0,p=typeof r==="number"&&r>=400&&r<500;return new g.KMsgError(p?g.KMsgErrorCode.INVALID_REQUEST:g.KMsgErrorCode.PROVIDER_ERROR,e.message,{providerId:t,httpStatus:r,errorCode:n.errorCode,errorMessage:n.errorMessage,url:n.url})}if(e instanceof b.ServerError)return new g.KMsgError(g.KMsgErrorCode.PROVIDER_ERROR,e.message,{providerId:t,httpStatus:typeof n.httpStatus==="number"?n.httpStatus:void 0});if(e instanceof b.DefaultError)return new g.KMsgError(g.KMsgErrorCode.PROVIDER_ERROR,e.message,{providerId:t,errorCode:n.errorCode,errorMessage:n.errorMessage});return new g.KMsgError(g.KMsgErrorCode.UNKNOWN_ERROR,e instanceof Error?e.message:String(e),{providerId:t})}var F=require("@k-msg/core");function ee(e){if(!e)return"UNKNOWN";if(e==="2000")return"PENDING";if(e==="3000")return"SENT";if(e==="4000")return"DELIVERED";if(/^[123]\\d{3}$/.test(e))return"FAILED";return"UNKNOWN"}function Q(e){if(typeof e!=="string"||e.trim().length===0)return;let t=new Date(e);if(Number.isNaN(t.getTime()))return;return t}function K(e){let t=e.trim();if(t.startsWith("+"))return`+${t.slice(1).replace(/\\D/g,"")}`;return t.replace(/\\D/g,"")}function w(e){let t={};if(!e)return t;for(let[n,r]of Object.entries(e)){if(r===void 0)continue;t[n]=r===null?"":r instanceof Date?r.toISOString():typeof r==="string"?r:String(r)}return t}function te(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e){if(!n)continue;if(n.type!=="WL")continue;if(!n.name||!n.urlMobile)continue;t.push({buttonName:n.name,buttonType:"WL",linkMo:n.urlMobile,linkPc:n.urlPc})}return t.length>0?t:void 0}function V(e){let t=typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0?e.imageUrl.trim():void 0;if(t)return t;let n=e.media?.image;if(!n)return;if("ref"in n){let r=n.ref.trim();return r.length>0?r:void 0}throw new F.KMsgError(F.KMsgErrorCode.INVALID_REQUEST,"SOLAPI image upload requires `options.imageUrl` or `options.media.image.ref` (url/path).",{providerId:e.providerId})}function P(e){return S(e)&&typeof e.fileId==="string"?e.fileId:void 0}function ne(e){switch(e.type){case"ALIMTALK":return"ATA";case"FRIENDTALK":return typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0||Boolean(e.media?.image)?"CTI":"CTA";default:return e.type}}async function ie(e){let{providerId:t,client:n,query:r}=e,p=r.providerMessageId.trim();if(!p)return R.fail(new R.KMsgError(R.KMsgErrorCode.INVALID_REQUEST,"providerMessageId is required",{providerId:t}));try{let o=await n.getMessages({messageId:p,limit:1}),k=(S(o)?o:{}).messageList;if(!k||typeof k!=="object"||Array.isArray(k))return R.ok(null);let l=k,E=l[p],q=Object.values(l).find((v)=>{if(!S(v))return!1;let L=v.messageId;return typeof L==="string"?L===p:!1}),h=S(E)?E:S(q)?q:void 0;if(!h)return R.ok(null);let I=typeof h.statusCode==="string"?h.statusCode:void 0,_=ee(I),A=Q(h.dateSent),O=Q(h.dateCompleted);return R.ok({providerId:t,providerMessageId:p,status:_,statusCode:I,statusMessage:typeof h.statusMessage==="string"?h.statusMessage:void 0,sentAt:A,deliveredAt:O,raw:h})}catch(o){return R.fail(T(o,t))}}var s=require("@k-msg/core");function ge(e,t){if(e.type!=="ALIMTALK")return;if(e.failover?.enabled!==!0)return;return[{code:"FAILOVER_PARTIAL_PROVIDER",message:"SOLAPI failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.",details:{providerId:t,mappedFields:["kakao.disableSms","text","subject"],unsupportedFields:["fallbackChannel"]}}]}function me(e){let{options:t,response:n,providerId:r,warnings:p}=e,o=S(n)?n:{},M=typeof o.messageId==="string"?o.messageId:void 0;return{messageId:t.messageId||crypto.randomUUID(),providerId:r,providerMessageId:M,status:"SENT",type:t.type,to:t.to,...Array.isArray(p)&&p.length>0?{warnings:p}:{},raw:n}}async function Ie(e){let{options:t,providerId:n,config:r,client:p}=e,o=ne(t),M=t.options?.scheduledAt,k=typeof t.from==="string"&&t.from.length>0?t.from:r.defaultFrom,l={to:K(t.to),type:o},E=typeof t.options?.country==="string"&&t.options.country.length>0?t.options.country:typeof r.defaultCountry==="string"?r.defaultCountry:void 0;if(E)l.country=E;let D=t.options?.customFields;if(D&&typeof D==="object"){let i={};for(let[a,d]of Object.entries(D)){if(d===void 0)continue;i[a]=typeof d==="string"?d:String(d)}if(Object.keys(i).length>0)l.customFields=i}if(M)l.scheduledDate=M;if(o==="SMS"||o==="LMS"||o==="MMS"||o==="VOICE"||o==="FAX"||String(o).startsWith("RCS_")){if(!k||k.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"from is required (options.from or config.defaultFrom)",{providerId:n,type:t.type});l.from=K(k)}else if(k)l.from=K(k);if(o==="SMS"||o==="LMS"||o==="MMS"){let i=t,a=i.text;if(a.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"text is required for SMS/LMS/MMS",{providerId:n,type:t.type});l.text=a;let d=i.subject;if(d)l.subject=d;if(o==="MMS"){let f=V({imageUrl:i.imageUrl,media:i.media,providerId:n});if(!f)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"image is required for MMS (options.imageUrl or options.media.image.ref)",{providerId:n});let u=await p.uploadFile(f,"MMS"),m=P(u);if(typeof m==="string"&&m.length>0)l.imageId=m;else throw new s.KMsgError(s.KMsgErrorCode.PROVIDER_ERROR,"Failed to upload MMS image",{providerId:n})}return l}if(o==="ATA"){let i=t,a=i.failover,d=typeof i.kakao?.profileId==="string"&&i.kakao.profileId.length>0?i.kakao.profileId:r.kakaoPfId;if(!d||d.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"kakao profileId is required (options.kakao.profileId or config.kakaoPfId)",{providerId:n});let f=typeof a?.fallbackContent==="string"&&a.fallbackContent.trim().length>0?a.fallbackContent.trim():void 0,u=typeof a?.fallbackTitle==="string"&&a.fallbackTitle.trim().length>0?a.fallbackTitle.trim():void 0,m=a?.enabled===!0?!1:a?.enabled===!1?!0:i.kakao?.disableSms;if(f)l.text=f;if(u)l.subject=u;return l.kakaoOptions={pfId:d,templateId:i.templateId,variables:w(i.variables),disableSms:m,adFlag:i.kakao?.adFlag,buttons:Array.isArray(i.kakao?.buttons)?i.kakao.buttons:void 0,imageId:i.kakao?.imageId},l}if(o==="CTA"||o==="CTI"){let i=t,a=i.text;if(a.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"text is required for FRIENDTALK",{providerId:n});let d=typeof i.kakao?.profileId==="string"&&i.kakao.profileId.length>0?i.kakao.profileId:r.kakaoPfId;if(!d||d.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"kakao profileId is required (options.kakao.profileId or config.kakaoPfId)",{providerId:n});let f=te(i.buttons),u=Array.isArray(i.kakao?.buttons)?i.kakao.buttons:f,m=typeof i.kakao?.imageLink==="string"&&i.kakao.imageLink.length>0?i.kakao.imageLink:void 0,C=Array.isArray(u)&&u.length>0?u[0]:void 0,x=S(C)&&typeof C.linkMo==="string"?C.linkMo:void 0,$=m??x,G;if(o==="CTI"){let H=V({imageUrl:i.imageUrl,media:i.media,providerId:n});if(!H)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"image is required for CTI (friendtalk image) (options.imageUrl or options.media.image.ref)",{providerId:n});if(!$)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"imageLink is required for friendtalk image upload (options.kakao.imageLink or WL button)",{providerId:n});let le=await p.uploadFile(H,"KAKAO",void 0,$),B=P(le);if(typeof B==="string"&&B.length>0)G=B;else throw new s.KMsgError(s.KMsgErrorCode.PROVIDER_ERROR,"Failed to upload friendtalk image",{providerId:n})}return l.text=a,l.kakaoOptions={pfId:d,variables:w(i.variables),disableSms:i.kakao?.disableSms,adFlag:i.kakao?.adFlag,buttons:u,imageId:G},l}if(o==="NSA"){let i=t,a=typeof i.naver?.talkId==="string"&&i.naver.talkId.length>0?i.naver.talkId:r.naverTalkId;if(!a||a.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"naver talkId is required (options.naver.talkId or config.naverTalkId)",{providerId:n});let d=typeof i.naver?.templateId==="string"&&i.naver.templateId.length>0?i.naver.templateId:i.templateId,f={...w(i.variables),...w(i.naver?.variables)};return l.naverOptions={talkId:a,templateId:d,variables:f,disableSms:i.naver?.disableSms,buttons:Array.isArray(i.naver?.buttons)?i.naver.buttons:void 0},l}if(o==="VOICE"){let i=t,a=i.text;if(a.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"text is required for VOICE",{providerId:n});let d=i.voice?.voiceType,f=d==="FEMALE"||d==="MALE"?d:"FEMALE";return l.text=a,l.voiceOptions=i.voice?{...i.voice,voiceType:f}:{voiceType:f},l}if(o==="FAX"){let a=t.fax,f=Array.isArray(a?.fileIds)?a.fileIds.filter((u)=>typeof u==="string"&&u.length>0):[];if(f.length===0){let u=Array.isArray(a?.fileUrls)?a.fileUrls.filter((m)=>typeof m==="string"&&m.length>0):[];if(u.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"fax.fileIds or fax.fileUrls is required",{providerId:n});f=[];for(let m of u){let C=await p.uploadFile(m,"FAX"),x=P(C);if(typeof x==="string"&&x.length>0)f.push(x)}}if(f.length===0)throw new s.KMsgError(s.KMsgErrorCode.PROVIDER_ERROR,"Failed to resolve fax fileIds",{providerId:n});return l.faxOptions={fileIds:f},l}let h=t,I=h.rcs,_=typeof I?.brandId==="string"&&I.brandId.length>0?I.brandId:r.rcsBrandId;if(!_||_.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"rcs brandId is required (options.rcs.brandId or config.rcsBrandId)",{providerId:n});let A={brandId:_,buttons:Array.isArray(I?.buttons)?I.buttons:void 0,copyAllowed:I?.copyAllowed,mmsType:I?.mmsType,commercialType:I?.commercialType,disableSms:I?.disableSms,variables:{...w(h.variables),...w(I?.variables)}};if(o==="RCS_TPL"||o==="RCS_ITPL"||o==="RCS_LTPL"){let i=t;A.templateId=typeof i.rcs?.templateId==="string"&&i.rcs.templateId.length>0?i.rcs.templateId:i.templateId}let O,v;if(o==="RCS_SMS"||o==="RCS_LMS"||o==="RCS_MMS"){let i=t;if(O=i.text,v=i.subject,!O||O.length===0)throw new s.KMsgError(s.KMsgErrorCode.INVALID_REQUEST,"text is required for RCS text types",{providerId:n});if(l.text=O,v)l.subject=v}let L=I?.additionalBody,y=S(L)?L:void 0,se=y&&typeof y.imageId==="string"&&y.imageId.length>0?y.imageId:y&&typeof y.imaggeId==="string"&&y.imaggeId.length>0?y.imaggeId:void 0,U=(i)=>{let a=y?{...y}:{},d=typeof a.title==="string"&&a.title.length>0?a.title:v||"RCS",f=typeof a.description==="string"&&a.description.length>0?a.description:O||"",u=se??i,m={...a,title:d,description:f};if(typeof u==="string"&&u.length>0)m.imaggeId=u;return m};if(o==="RCS_MMS"){let i=t,a=V({imageUrl:i.imageUrl,media:i.media,providerId:n});if(a){let d=await p.uploadFile(a,"RCS"),f=P(d);if(typeof f==="string"&&f.length>0)A.additionalBody=U(f);else if(y)A.additionalBody=U(void 0)}else if(y)A.additionalBody=U(void 0)}else if(y)A.additionalBody=U(void 0);return l.rcsOptions=A,l}async function re(e){let{providerId:t,client:n,config:r,options:p}=e,o=ge(p,t),M=await Ie({options:p,providerId:t,config:r,client:n}),k=await n.sendOne(M,r.appId);return s.ok(me({options:p,response:k,providerId:t,warnings:o}))}class N{id="solapi";name="SOLAPI Messaging Provider";supportedTypes=["ALIMTALK","FRIENDTALK","SMS","LMS","MMS","NSA","VOICE","FAX","RCS_SMS","RCS_LMS","RCS_MMS","RCS_TPL","RCS_ITPL","RCS_LTPL"];config;client;getOnboardingSpec(){let e=Z(this.id);if(!e)throw new c.KMsgError(c.KMsgErrorCode.INVALID_REQUEST,`Onboarding spec missing for provider: ${this.id}`,{providerId:this.id});return e}constructor(e,t){if(!e||typeof e!=="object")throw new c.KMsgError(c.KMsgErrorCode.INVALID_REQUEST,"SolapiProvider requires a config object",{providerId:this.id});if(!e.apiKey||e.apiKey.length===0)throw Error("SolapiProvider requires `apiKey`");if(!e.apiSecret||e.apiSecret.length===0)throw Error("SolapiProvider requires `apiSecret`");this.config={...e,baseUrl:typeof e.baseUrl==="string"&&e.baseUrl.length>0?e.baseUrl:"https://api.solapi.com"},this.client=t??new oe.SolapiMessageService(this.config.apiKey,this.config.apiSecret)}async healthCheck(){let e=[],t=Date.now();try{if(!this.config.apiKey)e.push("Missing apiKey");if(!this.config.apiSecret)e.push("Missing apiSecret");if(this.config.baseUrl)try{new URL(this.config.baseUrl)}catch{e.push("Invalid baseUrl")}return{healthy:e.length===0,issues:e,latencyMs:Date.now()-t,data:{provider:this.id,baseUrl:this.config.baseUrl}}}catch(n){return e.push(n instanceof Error?n.message:String(n)),{healthy:!1,issues:e,latencyMs:Date.now()-t}}}async send(e){let t=e.messageId||crypto.randomUUID(),n={...e,messageId:t};try{return await re({providerId:this.id,client:this.client,config:this.config,options:n})}catch(r){return c.fail(T(r,this.id))}}async getDeliveryStatus(e){return ie({providerId:this.id,client:this.client,query:e})}async getBalance(e){try{let t=await this.client.getBalance(),n=t,r=[n.balance,n.point],p=Number.NaN;for(let o of r){if(typeof o==="number"&&Number.isFinite(o)){p=o;break}if(typeof o==="string"){let M=Number(o);if(Number.isFinite(M)){p=M;break}}}if(!Number.isFinite(p))return c.fail(T(Error("Invalid balance response from SOLAPI"),this.id));return c.ok({providerId:this.id,channel:e?.channel,amount:p,currency:"KRW",raw:t})}catch(t){return c.fail(T(t,this.id))}}}var W=(e)=>new N(e),X=()=>{let e={apiKey:c.readRuntimeEnv("SOLAPI_API_KEY")||"",apiSecret:c.readRuntimeEnv("SOLAPI_API_SECRET")||"",baseUrl:c.readRuntimeEnv("SOLAPI_BASE_URL")||"https://api.solapi.com",defaultFrom:c.readRuntimeEnv("SOLAPI_DEFAULT_FROM"),kakaoPfId:c.readRuntimeEnv("SOLAPI_KAKAO_PF_ID"),rcsBrandId:c.readRuntimeEnv("SOLAPI_RCS_BRAND_ID"),naverTalkId:c.readRuntimeEnv("SOLAPI_NAVER_TALK_ID"),appId:c.readRuntimeEnv("SOLAPI_APP_ID"),defaultCountry:c.readRuntimeEnv("SOLAPI_DEFAULT_COUNTRY"),debug:c.readRuntimeEnv("NODE_ENV")==="development"};if(!e.apiKey||!e.apiSecret)throw Error("SOLAPI_API_KEY and SOLAPI_API_SECRET environment variables are required");return W(e)};class z{static create(e){return new N(e)}static createDefault(){return X()}}function ae(){}
2
2
 
3
- //# debugId=AA25F66A5E1E847664756E2164756E21
3
+ //# debugId=22D7FD78E1A81A5164756E2164756E21
4
4
  //# sourceMappingURL=index.js.map
@@ -1,19 +1,16 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../core/src/errors.ts", "../../core/src/result.ts", "../../core/src/runtime/env.ts", "../src/solapi/provider.ts", "../src/onboarding/specs.ts", "../src/shared/type-guards.ts", "../src/solapi/solapi.error.ts", "../src/solapi/solapi.helpers.ts", "../src/solapi/solapi.delivery.ts", "../src/solapi/solapi.send.ts"],
3
+ "sources": ["../src/solapi/provider.ts", "../src/onboarding/specs.ts", "../src/solapi/solapi.delivery.ts", "../src/shared/type-guards.ts", "../src/solapi/solapi.error.ts", "../src/solapi/solapi.helpers.ts", "../src/solapi/solapi.send.ts"],
4
4
  "sourcesContent": [
5
- "export type Locale = \"ko\" | \"en\";\n\nexport enum KMsgErrorCode {\n INVALID_REQUEST = \"INVALID_REQUEST\",\n AUTHENTICATION_FAILED = \"AUTHENTICATION_FAILED\",\n INSUFFICIENT_BALANCE = \"INSUFFICIENT_BALANCE\",\n TEMPLATE_NOT_FOUND = \"TEMPLATE_NOT_FOUND\",\n RATE_LIMIT_EXCEEDED = \"RATE_LIMIT_EXCEEDED\",\n NETWORK_ERROR = \"NETWORK_ERROR\",\n NETWORK_TIMEOUT = \"NETWORK_TIMEOUT\",\n NETWORK_SERVICE_UNAVAILABLE = \"NETWORK_SERVICE_UNAVAILABLE\",\n PROVIDER_ERROR = \"PROVIDER_ERROR\",\n MESSAGE_SEND_FAILED = \"MESSAGE_SEND_FAILED\",\n CRYPTO_CONFIG_ERROR = \"CRYPTO_CONFIG_ERROR\",\n CRYPTO_ENCRYPT_FAILED = \"CRYPTO_ENCRYPT_FAILED\",\n CRYPTO_DECRYPT_FAILED = \"CRYPTO_DECRYPT_FAILED\",\n CRYPTO_HASH_FAILED = \"CRYPTO_HASH_FAILED\",\n CRYPTO_POLICY_VIOLATION = \"CRYPTO_POLICY_VIOLATION\",\n UNKNOWN_ERROR = \"UNKNOWN_ERROR\",\n}\n\nconst DEFAULT_LOCALE: Locale = \"ko\";\n\nconst ERROR_MESSAGES: Record<KMsgErrorCode, { ko: string; en: string }> = {\n [KMsgErrorCode.INVALID_REQUEST]: {\n ko: \"잘못된 요청입니다\",\n en: \"Invalid request\",\n },\n [KMsgErrorCode.AUTHENTICATION_FAILED]: {\n ko: \"인증에 실패했습니다\",\n en: \"Authentication failed\",\n },\n [KMsgErrorCode.INSUFFICIENT_BALANCE]: {\n ko: \"잔액이 부족합니다\",\n en: \"Insufficient balance\",\n },\n [KMsgErrorCode.TEMPLATE_NOT_FOUND]: {\n ko: \"템플릿을 찾을 수 없습니다\",\n en: \"Template not found\",\n },\n [KMsgErrorCode.RATE_LIMIT_EXCEEDED]: {\n ko: \"요청 한도를 초과했습니다\",\n en: \"Rate limit exceeded\",\n },\n [KMsgErrorCode.NETWORK_ERROR]: {\n ko: \"네트워크 오류가 발생했습니다\",\n en: \"Network error\",\n },\n [KMsgErrorCode.NETWORK_TIMEOUT]: {\n ko: \"네트워크 요청 시간이 초과되었습니다\",\n en: \"Network timeout\",\n },\n [KMsgErrorCode.NETWORK_SERVICE_UNAVAILABLE]: {\n ko: \"서비스를 일시적으로 사용할 수 없습니다\",\n en: \"Service temporarily unavailable\",\n },\n [KMsgErrorCode.PROVIDER_ERROR]: {\n ko: \"제공자 오류가 발생했습니다\",\n en: \"Provider error\",\n },\n [KMsgErrorCode.MESSAGE_SEND_FAILED]: {\n ko: \"메시지 전송에 실패했습니다\",\n en: \"Message send failed\",\n },\n [KMsgErrorCode.CRYPTO_CONFIG_ERROR]: {\n ko: \"암호화 설정 오류가 발생했습니다\",\n en: \"Crypto configuration error\",\n },\n [KMsgErrorCode.CRYPTO_ENCRYPT_FAILED]: {\n ko: \"암호화에 실패했습니다\",\n en: \"Encryption failed\",\n },\n [KMsgErrorCode.CRYPTO_DECRYPT_FAILED]: {\n ko: \"복호화에 실패했습니다\",\n en: \"Decryption failed\",\n },\n [KMsgErrorCode.CRYPTO_HASH_FAILED]: {\n ko: \"해시 생성에 실패했습니다\",\n en: \"Hash generation failed\",\n },\n [KMsgErrorCode.CRYPTO_POLICY_VIOLATION]: {\n ko: \"암호화 정책 위반이 발생했습니다\",\n en: \"Crypto policy violation\",\n },\n [KMsgErrorCode.UNKNOWN_ERROR]: {\n ko: \"알 수 없는 오류가 발생했습니다\",\n en: \"Unknown error\",\n },\n};\n\nexport type RetryPolicyErrorCode = KMsgErrorCode;\n\nexport type ProviderRetryHint = \"retryable\" | \"non_retryable\";\n\nexport interface KMsgErrorMetadata {\n providerErrorCode?: string;\n providerErrorText?: string;\n httpStatus?: number;\n requestId?: string;\n retryAfterMs?: number;\n attempt?: number;\n causeChain?: unknown[];\n}\n\nexport interface ErrorRetryPolicy {\n retryableCodes?: readonly KMsgErrorCode[];\n nonRetryableCodes?: readonly KMsgErrorCode[];\n classifyByStatusCode?: (status: number) => ProviderRetryHint;\n classifyByMessage?: (message: string) => ProviderRetryHint | undefined;\n /**\n * Optional override for retry hint inference.\n */\n fallback?: ProviderRetryHint;\n /**\n * Optional custom retry delay in milliseconds.\n */\n retryAfterMs?: (error: KMsgError) => number | undefined;\n}\n\nconst DEFAULT_RETRYABLE_ERROR_CODES: ReadonlySet<RetryPolicyErrorCode> =\n new Set([\n KMsgErrorCode.NETWORK_ERROR,\n KMsgErrorCode.RATE_LIMIT_EXCEEDED,\n KMsgErrorCode.NETWORK_TIMEOUT,\n KMsgErrorCode.NETWORK_SERVICE_UNAVAILABLE,\n KMsgErrorCode.PROVIDER_ERROR,\n KMsgErrorCode.UNKNOWN_ERROR,\n ]);\n\nconst DEFAULT_NON_RETRYABLE_ERROR_CODES: ReadonlySet<RetryPolicyErrorCode> =\n new Set([\n KMsgErrorCode.INVALID_REQUEST,\n KMsgErrorCode.AUTHENTICATION_FAILED,\n KMsgErrorCode.INSUFFICIENT_BALANCE,\n KMsgErrorCode.TEMPLATE_NOT_FOUND,\n KMsgErrorCode.MESSAGE_SEND_FAILED,\n KMsgErrorCode.CRYPTO_CONFIG_ERROR,\n KMsgErrorCode.CRYPTO_ENCRYPT_FAILED,\n KMsgErrorCode.CRYPTO_DECRYPT_FAILED,\n KMsgErrorCode.CRYPTO_HASH_FAILED,\n KMsgErrorCode.CRYPTO_POLICY_VIOLATION,\n ]);\n\nconst normalizeNumber = (value: unknown): number | undefined => {\n if (\n typeof value !== \"number\" ||\n Number.isNaN(value) ||\n !Number.isFinite(value)\n ) {\n return undefined;\n }\n\n return Math.trunc(value);\n};\n\nexport const normalizeRetryAfterMs = (value: unknown): number | undefined => {\n const normalized = normalizeNumber(value);\n if (normalized === undefined || normalized < 0) {\n return undefined;\n }\n\n return normalized;\n};\n\nconst toLowerString = (value: unknown): string | undefined => {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n return value.toLowerCase().trim();\n};\n\nconst classifyByHttpStatus = (status: number): ProviderRetryHint => {\n if (status >= 500) {\n return \"retryable\";\n }\n\n if (status === 408 || status === 425 || status === 429) {\n return \"retryable\";\n }\n\n return \"non_retryable\";\n};\n\nconst classifyByMessage = (message: string): ProviderRetryHint | undefined => {\n const normalized = message.toLowerCase();\n\n if (\n normalized.includes(\"timeout\") ||\n normalized.includes(\"temporar\") ||\n normalized.includes(\"network\") ||\n normalized.includes(\"retry\")\n ) {\n return \"retryable\";\n }\n\n return undefined;\n};\n\nexport class KMsgError extends Error {\n public readonly code: KMsgErrorCode;\n public readonly details?: Record<string, unknown>;\n public readonly providerErrorCode?: string;\n public readonly providerErrorText?: string;\n public readonly httpStatus?: number;\n public readonly requestId?: string;\n public readonly retryAfterMs?: number;\n public readonly attempt?: number;\n public readonly causeChain?: unknown[];\n\n constructor(\n code: KMsgErrorCode,\n message: string,\n details?: Record<string, unknown>,\n metadata: KMsgErrorMetadata = {},\n ) {\n super(message);\n this.name = \"KMsgError\";\n this.code = code;\n this.details = details;\n\n this.providerErrorCode = metadata.providerErrorCode;\n this.providerErrorText = metadata.providerErrorText;\n this.httpStatus = normalizeNumber(metadata.httpStatus);\n this.requestId =\n typeof metadata.requestId === \"string\" ? metadata.requestId : undefined;\n this.retryAfterMs = normalizeNumber(metadata.retryAfterMs);\n this.attempt = normalizeNumber(metadata.attempt);\n\n if (Array.isArray(metadata.causeChain)) {\n this.causeChain = metadata.causeChain;\n } else if (metadata.causeChain !== undefined) {\n this.causeChain = [metadata.causeChain];\n }\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, KMsgError);\n }\n }\n\n /**\n * Returns a localized error message based on the provided locale.\n * Falls back to Korean (default) if locale is not provided.\n * Falls back to the original message if no localized message exists.\n */\n getLocalizedMessage(locale: Locale = DEFAULT_LOCALE): string {\n const messages = ERROR_MESSAGES[this.code];\n if (messages?.[locale]) {\n return messages[locale];\n }\n return this.message;\n }\n\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n details: this.details,\n providerErrorCode: this.providerErrorCode,\n providerErrorText: this.providerErrorText,\n httpStatus: this.httpStatus,\n requestId: this.requestId,\n retryAfterMs: this.retryAfterMs,\n attempt: this.attempt,\n causeChain: this.causeChain,\n };\n }\n}\n\nexport const ErrorUtils = {\n isRetryable(error: unknown, policy: ErrorRetryPolicy = {}): boolean {\n return ErrorUtils.classifyForRetry(error, policy) === \"retryable\";\n },\n\n classifyForRetry(\n error: unknown,\n policy: ErrorRetryPolicy = {},\n ): ProviderRetryHint {\n if (error instanceof KMsgError) {\n const retryableCodes = new Set(\n policy.retryableCodes ?? Array.from(DEFAULT_RETRYABLE_ERROR_CODES),\n );\n if (retryableCodes.has(error.code)) {\n return \"retryable\";\n }\n\n const nonRetryableCodes = new Set(\n policy.nonRetryableCodes ??\n Array.from(DEFAULT_NON_RETRYABLE_ERROR_CODES),\n );\n if (nonRetryableCodes.has(error.code)) {\n return \"non_retryable\";\n }\n\n if (error.httpStatus !== undefined) {\n return classifyByHttpStatus(error.httpStatus);\n }\n\n const classifiedByMessage = classifyByMessage(error.message);\n if (classifiedByMessage) {\n return classifiedByMessage;\n }\n\n if (policy.classifyByMessage && error.message) {\n const classified = policy.classifyByMessage(error.message);\n if (classified) {\n return classified;\n }\n }\n\n if (policy.fallback) {\n return policy.fallback;\n }\n\n return \"non_retryable\";\n }\n\n const candidate =\n error && typeof error === \"object\"\n ? (error as {\n status?: unknown;\n statusCode?: unknown;\n httpStatus?: unknown;\n code?: unknown;\n message?: unknown;\n })\n : undefined;\n\n const status =\n toLowerString(candidate?.status) ??\n toLowerString(candidate?.statusCode) ??\n toLowerString(candidate?.code);\n const statusCode =\n normalizeNumber(candidate?.status) ??\n normalizeNumber(candidate?.statusCode) ??\n normalizeNumber(candidate?.httpStatus);\n\n if (typeof status === \"string\" && status.startsWith(\"5\")) {\n return \"retryable\";\n }\n\n if (statusCode !== undefined) {\n if (policy.classifyByStatusCode) {\n return policy.classifyByStatusCode(statusCode);\n }\n\n return classifyByHttpStatus(statusCode);\n }\n\n const classifiedByMessage =\n typeof candidate?.message === \"string\"\n ? classifyByMessage(candidate.message)\n : undefined;\n\n if (classifiedByMessage) {\n return classifiedByMessage;\n }\n\n if (policy.classifyByMessage && typeof candidate?.message === \"string\") {\n const classified = policy.classifyByMessage(candidate.message);\n if (classified) {\n return classified;\n }\n }\n\n return policy.fallback ?? \"non_retryable\";\n },\n\n resolveRetryAfterMs(\n error: KMsgError,\n policy?: ErrorRetryPolicy,\n ): number | undefined {\n if (policy?.retryAfterMs) {\n const override = policy.retryAfterMs(error);\n const normalized = normalizeRetryAfterMs(override);\n if (normalized !== undefined) {\n return normalized;\n }\n }\n\n if (error.retryAfterMs !== undefined) {\n return normalizeRetryAfterMs(error.retryAfterMs);\n }\n\n if (\n error.code === KMsgErrorCode.RATE_LIMIT_EXCEEDED &&\n error.retryAfterMs === undefined\n ) {\n return undefined;\n }\n\n return undefined;\n },\n\n isUnknownStatus: (statusCode: number | undefined): boolean => {\n if (\n statusCode === undefined ||\n Number.isNaN(statusCode) ||\n !Number.isFinite(statusCode)\n ) {\n return false;\n }\n\n return statusCode < 500;\n },\n\n toRetryMetadata(error: KMsgError): KMsgErrorMetadata {\n return {\n providerErrorCode: error.providerErrorCode,\n providerErrorText: error.providerErrorText,\n httpStatus: error.httpStatus,\n requestId: error.requestId,\n retryAfterMs: error.retryAfterMs,\n attempt: error.attempt,\n causeChain: error.causeChain,\n };\n },\n\n withAttempt(error: KMsgError, attempt: number): KMsgError {\n return new KMsgError(error.code, error.message, error.details, {\n ...ErrorUtils.toRetryMetadata(error),\n attempt: normalizeNumber(attempt),\n });\n },\n\n DEFAULT_RETRYABLE_ERROR_CODES,\n DEFAULT_NON_RETRYABLE_ERROR_CODES,\n};\n",
6
- "/**\n * Represents a successful result containing a value.\n */\nexport type Ok<T> = {\n /** Always true for successful results. */\n readonly isSuccess: true;\n /** Always false for successful results. */\n readonly isFailure: false;\n /** The contained success value. */\n readonly value: T;\n};\n\n/**\n * Represents a failed result containing an error.\n */\nexport type Fail<E> = {\n /** Always false for failed results. */\n readonly isSuccess: false;\n /** Always true for failed results. */\n readonly isFailure: true;\n /** The contained error. */\n readonly error: E;\n};\n\n/**\n * A result type that represents either success (Ok) or failure (Fail).\n * Used throughout k-msg for explicit error handling without exceptions.\n *\n * @template T - The type of the success value\n * @template E - The type of the error (defaults to Error)\n *\n * @example\n * ```ts\n * function divide(a: number, b: number): Result<number, string> {\n * if (b === 0) return fail(\"division by zero\");\n * return ok(a / b);\n * }\n *\n * const result = divide(10, 2);\n * if (result.isSuccess) {\n * console.log(result.value); // 5\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport type Result<T, E = Error> = Ok<T> | Fail<E>;\n\n/**\n * Create a successful result containing the given value.\n * @param value - The success value to wrap\n * @returns An Ok result containing the value\n */\nexport const ok = <T>(value: T): Ok<T> => ({\n isSuccess: true,\n isFailure: false,\n value,\n});\n\n/**\n * Create a failed result containing the given error.\n * @param error - The error to wrap\n * @returns A Fail result containing the error\n */\nexport const fail = <E>(error: E): Fail<E> => ({\n isSuccess: false,\n isFailure: true,\n error,\n});\n\n/**\n * Result utility functions for chaining and transformation\n */\nexport const Result = {\n /**\n * Transform the success value of a Result\n */\n map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {\n if (result.isSuccess) {\n return ok(fn(result.value));\n }\n return result;\n },\n\n /**\n * Chain Result-returning operations\n */\n flatMap<T, U, E>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, E>,\n ): Result<U, E> {\n if (result.isSuccess) {\n return fn(result.value);\n }\n return result;\n },\n\n /**\n * Transform the error of a Result\n */\n mapError<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> {\n if (result.isFailure) {\n return fail(fn(result.error));\n }\n return result;\n },\n\n /**\n * Extract the value or throw the error\n */\n unwrap<T, E>(result: Result<T, E>): T {\n if (result.isSuccess) {\n return result.value;\n }\n throw result.error;\n },\n\n /**\n * Extract the value or return a default\n */\n unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {\n if (result.isSuccess) {\n return result.value;\n }\n return defaultValue;\n },\n\n /**\n * Extract the value or compute a default from the error\n */\n unwrapOrElse<T, E>(result: Result<T, E>, fn: (error: E) => T): T {\n if (result.isSuccess) {\n return result.value;\n }\n return fn(result.error);\n },\n\n /**\n * Pattern match on a Result\n */\n match<T, E, U>(\n result: Result<T, E>,\n handlers: { ok: (value: T) => U; fail: (error: E) => U },\n ): U {\n if (result.isSuccess) {\n return handlers.ok(result.value);\n }\n return handlers.fail(result.error);\n },\n\n /**\n * Convert a Promise to a Result\n */\n async fromPromise<T, E = Error>(promise: Promise<T>): Promise<Result<T, E>> {\n try {\n const value = await promise;\n return ok(value);\n } catch (error) {\n return fail(error as E);\n }\n },\n\n /**\n * Check if a Result is Ok\n */\n isOk<T, E>(result: Result<T, E>): result is Ok<T> {\n return result.isSuccess;\n },\n\n /**\n * Check if a Result is Fail\n */\n isFail<T, E>(result: Result<T, E>): result is Fail<E> {\n return result.isFailure;\n },\n\n /**\n * Execute a side-effect without breaking the chain.\n * Calls fn with the result (ok or fail) and returns the same result.\n *\n * @param result - The Result to tap\n * @param fn - Side-effect function called with the result\n * @returns The same Result for chaining\n *\n * @example\n * ```ts\n * const result = await provider.send(options);\n * Result.tap(result, r => console.log('Completed:', r));\n * ```\n */\n tap<T, E>(\n result: Result<T, E>,\n fn: (result: Result<T, E>) => void,\n ): Result<T, E> {\n fn(result);\n return result;\n },\n\n /**\n * Execute a side-effect on success only.\n * Calls fn with the value only if result is ok, returns the same result.\n *\n * @param result - The Result to tap\n * @param fn - Side-effect function called with the value on success\n * @returns The same Result for chaining\n *\n * @example\n * ```ts\n * Result.tapOk(result, value => console.log('Success:', value.messageId));\n * ```\n */\n tapOk<T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E> {\n if (result.isSuccess) {\n fn(result.value);\n }\n return result;\n },\n\n /**\n * Execute a side-effect on failure only.\n * Calls fn with the error only if result is fail, returns the same result.\n *\n * @param result - The Result to tap\n * @param fn - Side-effect function called with the error on failure\n * @returns The same Result for chaining\n *\n * @example\n * ```ts\n * Result.tapErr(result, error => console.error('Failed:', error.message));\n * ```\n */\n tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E> {\n if (result.isFailure) {\n fn(result.error);\n }\n return result;\n },\n\n /**\n * Return the value on success, or throw with a custom message on failure.\n * Use this when you want to convert a failed Result to an exception.\n *\n * @param result - The Result to expect\n * @param message - Custom error message to use if result is fail\n * @returns The success value\n * @throws Error with the provided message (and original error as cause)\n *\n * @example\n * ```ts\n * const value = Result.expect(result, 'Message send failed');\n * // throws Error('Message send failed') if result is fail\n * ```\n */\n expect<T, E>(result: Result<T, E>, message: string): T {\n if (result.isSuccess) {\n return result.value;\n }\n throw new Error(message, { cause: result.error });\n },\n};\n",
7
- "export type RuntimeEnvRecord = Record<string, string | undefined>;\n\ntype RuntimeGlobal = typeof globalThis & {\n __ENV__?: RuntimeEnvRecord;\n __K_MSG_ENV__?: RuntimeEnvRecord;\n process?: {\n env?: RuntimeEnvRecord;\n };\n};\n\n/**\n * Resolve environment variables in a runtime-neutral order.\n *\n * Priority:\n * 1. globalThis.__K_MSG_ENV__\n * 2. globalThis.__ENV__\n * 3. globalThis.process?.env\n */\nexport function getRuntimeEnvSource(): RuntimeEnvRecord {\n const runtimeGlobal = globalThis as RuntimeGlobal;\n return (\n runtimeGlobal.__K_MSG_ENV__ ??\n runtimeGlobal.__ENV__ ??\n runtimeGlobal.process?.env ??\n {}\n );\n}\n\nexport function readRuntimeEnv(key: string): string | undefined {\n const value = getRuntimeEnvSource()[key];\n if (typeof value === \"string\") {\n return value;\n }\n if (value === undefined) {\n return undefined;\n }\n return String(value);\n}\n",
8
5
  "import {\n type BalanceProvider,\n type BalanceQuery,\n type BalanceResult,\n type DeliveryStatusQuery,\n type DeliveryStatusResult,\n fail,\n KMsgError,\n KMsgErrorCode,\n type MessageType,\n ok,\n type Provider,\n type ProviderHealthStatus,\n type Result,\n readRuntimeEnv,\n type SendOptions,\n type SendResult,\n} from \"@k-msg/core\";\nimport { SolapiMessageService } from \"solapi\";\nimport { getProviderOnboardingSpec } from \"../onboarding/specs\";\nimport { getSolapiDeliveryStatus } from \"./solapi.delivery\";\nimport { mapSolapiError } from \"./solapi.error\";\nimport type { SolapiSdkClient } from \"./solapi.internal.types\";\nimport { sendWithSolapi } from \"./solapi.send\";\nimport type { SolapiConfig } from \"./types/solapi\";\n\nexport class SolapiProvider implements Provider, BalanceProvider {\n readonly id = \"solapi\";\n readonly name = \"SOLAPI Messaging Provider\";\n readonly supportedTypes: readonly MessageType[] = [\n \"ALIMTALK\",\n \"FRIENDTALK\",\n \"SMS\",\n \"LMS\",\n \"MMS\",\n \"NSA\",\n \"VOICE\",\n \"FAX\",\n \"RCS_SMS\",\n \"RCS_LMS\",\n \"RCS_MMS\",\n \"RCS_TPL\",\n \"RCS_ITPL\",\n \"RCS_LTPL\",\n ];\n\n private readonly config: SolapiConfig;\n private readonly client: SolapiSdkClient;\n\n getOnboardingSpec() {\n const spec = getProviderOnboardingSpec(this.id);\n if (!spec) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `Onboarding spec missing for provider: ${this.id}`,\n { providerId: this.id },\n );\n }\n return spec;\n }\n\n constructor(config: SolapiConfig, client?: SolapiSdkClient) {\n if (!config || typeof config !== \"object\") {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"SolapiProvider requires a config object\",\n { providerId: this.id },\n );\n }\n if (!config.apiKey || config.apiKey.length === 0) {\n throw new Error(\"SolapiProvider requires `apiKey`\");\n }\n if (!config.apiSecret || config.apiSecret.length === 0) {\n throw new Error(\"SolapiProvider requires `apiSecret`\");\n }\n\n this.config = {\n ...config,\n baseUrl:\n typeof config.baseUrl === \"string\" && config.baseUrl.length > 0\n ? config.baseUrl\n : \"https://api.solapi.com\",\n };\n this.client =\n client ??\n new SolapiMessageService(this.config.apiKey, this.config.apiSecret);\n }\n\n async healthCheck(): Promise<ProviderHealthStatus> {\n const issues: string[] = [];\n const start = Date.now();\n\n try {\n if (!this.config.apiKey) issues.push(\"Missing apiKey\");\n if (!this.config.apiSecret) issues.push(\"Missing apiSecret\");\n if (this.config.baseUrl) {\n try {\n new URL(this.config.baseUrl);\n } catch {\n issues.push(\"Invalid baseUrl\");\n }\n }\n\n return {\n healthy: issues.length === 0,\n issues,\n latencyMs: Date.now() - start,\n data: {\n provider: this.id,\n baseUrl: this.config.baseUrl,\n },\n };\n } catch (error) {\n issues.push(error instanceof Error ? error.message : String(error));\n return { healthy: false, issues, latencyMs: Date.now() - start };\n }\n }\n\n async send(options: SendOptions): Promise<Result<SendResult, KMsgError>> {\n const messageId = options.messageId || crypto.randomUUID();\n const normalized = { ...options, messageId } as SendOptions;\n\n try {\n return await sendWithSolapi({\n providerId: this.id,\n client: this.client,\n config: this.config,\n options: normalized,\n });\n } catch (error) {\n return fail(mapSolapiError(error, this.id));\n }\n }\n\n async getDeliveryStatus(\n query: DeliveryStatusQuery,\n ): Promise<Result<DeliveryStatusResult | null, KMsgError>> {\n return getSolapiDeliveryStatus({\n providerId: this.id,\n client: this.client,\n query,\n });\n }\n\n async getBalance(\n query?: BalanceQuery,\n ): Promise<Result<BalanceResult, KMsgError>> {\n try {\n const raw = await this.client.getBalance();\n const source = raw as Record<string, unknown>;\n const amountCandidates = [source.balance, source.point];\n\n let amount = Number.NaN;\n for (const candidate of amountCandidates) {\n if (typeof candidate === \"number\" && Number.isFinite(candidate)) {\n amount = candidate;\n break;\n }\n if (typeof candidate === \"string\") {\n const numeric = Number(candidate);\n if (Number.isFinite(numeric)) {\n amount = numeric;\n break;\n }\n }\n }\n\n if (!Number.isFinite(amount)) {\n return fail(\n mapSolapiError(\n new Error(\"Invalid balance response from SOLAPI\"),\n this.id,\n ),\n );\n }\n\n return ok({\n providerId: this.id,\n channel: query?.channel,\n amount,\n currency: \"KRW\",\n raw,\n });\n } catch (error) {\n return fail(mapSolapiError(error, this.id));\n }\n }\n}\n\nexport const createSolapiProvider = (config: SolapiConfig) =>\n new SolapiProvider(config);\n\nexport const createDefaultSolapiProvider = () => {\n const config: SolapiConfig = {\n apiKey: readRuntimeEnv(\"SOLAPI_API_KEY\") || \"\",\n apiSecret: readRuntimeEnv(\"SOLAPI_API_SECRET\") || \"\",\n baseUrl: readRuntimeEnv(\"SOLAPI_BASE_URL\") || \"https://api.solapi.com\",\n defaultFrom: readRuntimeEnv(\"SOLAPI_DEFAULT_FROM\"),\n kakaoPfId: readRuntimeEnv(\"SOLAPI_KAKAO_PF_ID\"),\n rcsBrandId: readRuntimeEnv(\"SOLAPI_RCS_BRAND_ID\"),\n naverTalkId: readRuntimeEnv(\"SOLAPI_NAVER_TALK_ID\"),\n appId: readRuntimeEnv(\"SOLAPI_APP_ID\"),\n defaultCountry: readRuntimeEnv(\"SOLAPI_DEFAULT_COUNTRY\"),\n debug: readRuntimeEnv(\"NODE_ENV\") === \"development\",\n };\n\n if (!config.apiKey || !config.apiSecret) {\n throw new Error(\n \"SOLAPI_API_KEY and SOLAPI_API_SECRET environment variables are required\",\n );\n }\n\n return createSolapiProvider(config);\n};\n\n// biome-ignore lint/complexity/noStaticOnlyClass: kept as a factory for convenience\nexport class SolapiProviderFactory {\n static create(config: SolapiConfig): SolapiProvider {\n return new SolapiProvider(config);\n }\n\n static createDefault(): SolapiProvider {\n return createDefaultSolapiProvider();\n }\n}\n\nexport function initializeSolapi(): void {}\n",
9
6
  "import type { ProviderOnboardingSpec } from \"@k-msg/core\";\n\nexport const providerOnboardingSpecs: Readonly<\n Record<string, ProviderOnboardingSpec>\n> = {\n iwinv: {\n providerId: \"iwinv\",\n providerName: \"IWINV Messaging Provider\",\n channelOnboarding: \"manual\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"optional\",\n plusIdInference: \"unsupported\",\n liveTestSupport: \"supported\",\n checks: [\n {\n id: \"channel_registered_in_console\",\n title: \"Kakao channel is registered in IWINV console\",\n description:\n \"IWINV channel onboarding is manual. Confirm channel registration and approval in console.\",\n kind: \"manual\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n },\n {\n id: \"iwinv_config_required\",\n title: \"IWINV config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\"],\n },\n {\n id: \"template_capability_available\",\n title: \"Template lifecycle APIs are available\",\n kind: \"capability\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\n \"listTemplates\",\n \"getTemplate\",\n \"createTemplate\",\n \"updateTemplate\",\n \"deleteTemplate\",\n ],\n },\n {\n id: \"template_list_probe\",\n title: \"Template list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_templates\",\n },\n ],\n notes: [\n \"Channel add/auth is not available via IWINV public API in current integration.\",\n \"Template APIs are available and can be probed.\",\n ],\n },\n aligo: {\n providerId: \"aligo\",\n providerName: \"Aligo Smart SMS\",\n channelOnboarding: \"api\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"required_if_no_inference\",\n plusIdInference: \"supported\",\n liveTestSupport: \"supported\",\n checks: [\n {\n id: \"aligo_config_required\",\n title: \"Aligo config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\", \"userId\"],\n },\n {\n id: \"channel_api_capability_available\",\n title: \"Kakao channel APIs are available\",\n kind: \"capability\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\n \"listKakaoChannels\",\n \"requestKakaoChannelAuth\",\n \"addKakaoChannel\",\n ],\n },\n {\n id: \"channel_list_probe\",\n title: \"Kakao channel list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_kakao_channels\",\n },\n {\n id: \"template_list_probe\",\n title: \"Template list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_templates\",\n },\n ],\n },\n solapi: {\n providerId: \"solapi\",\n providerName: \"SOLAPI Messaging Provider\",\n channelOnboarding: \"none\",\n templateLifecycleApi: \"unavailable\",\n plusIdPolicy: \"required_if_no_inference\",\n plusIdInference: \"unsupported\",\n liveTestSupport: \"partial\",\n checks: [\n {\n id: \"solapi_config_required\",\n title: \"SOLAPI config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\", \"apiSecret\"],\n },\n ],\n notes: [\n \"SOLAPI ALIMTALK requires kakao profileId/pfId, but plusId inference is not available in current integration.\",\n ],\n },\n mock: {\n providerId: \"mock\",\n providerName: \"Mock Provider\",\n channelOnboarding: \"api\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"optional\",\n plusIdInference: \"supported\",\n liveTestSupport: \"none\",\n checks: [\n {\n id: \"mock_template_capability_available\",\n title: \"Mock template APIs are available\",\n kind: \"capability\",\n severity: \"info\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\"listTemplates\", \"getTemplate\", \"createTemplate\"],\n },\n ],\n },\n} as const;\n\nexport function getProviderOnboardingSpec(\n providerId: string,\n): ProviderOnboardingSpec | undefined {\n return providerOnboardingSpecs[providerId];\n}\n\nexport function listProviderOnboardingSpecs(): ProviderOnboardingSpec[] {\n return Object.values(providerOnboardingSpecs);\n}\n",
7
+ "import {\n type DeliveryStatusQuery,\n type DeliveryStatusResult,\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport { mapSolapiError } from \"./solapi.error\";\nimport { mapSolapiStatusCode, parseDate } from \"./solapi.helpers\";\nimport type { SolapiSdkClient } from \"./solapi.internal.types\";\n\nexport async function getSolapiDeliveryStatus(params: {\n providerId: string;\n client: SolapiSdkClient;\n query: DeliveryStatusQuery;\n}): Promise<Result<DeliveryStatusResult | null, KMsgError>> {\n const { providerId, client, query } = params;\n const providerMessageId = query.providerMessageId.trim();\n if (!providerMessageId) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"providerMessageId is required\",\n { providerId },\n ),\n );\n }\n\n try {\n const response = await client.getMessages({\n messageId: providerMessageId,\n limit: 1,\n });\n\n const record = (isObjectRecord(response) ? response : {}) as Record<\n string,\n unknown\n >;\n const messageList = record.messageList;\n if (\n !messageList ||\n typeof messageList !== \"object\" ||\n Array.isArray(messageList)\n ) {\n return ok(null);\n }\n\n const recordList = messageList as Record<string, unknown>;\n const direct = recordList[providerMessageId];\n\n const values = Object.values(recordList);\n const found = values.find((v) => {\n if (!isObjectRecord(v)) return false;\n const mid = v.messageId;\n return typeof mid === \"string\" ? mid === providerMessageId : false;\n });\n\n const message = isObjectRecord(direct)\n ? direct\n : isObjectRecord(found)\n ? found\n : undefined;\n if (!message) return ok(null);\n\n const statusCode =\n typeof message.statusCode === \"string\" ? message.statusCode : undefined;\n const status = mapSolapiStatusCode(statusCode);\n\n const sentAt = parseDate(message.dateSent);\n const deliveredAt = parseDate(message.dateCompleted);\n\n return ok({\n providerId,\n providerMessageId,\n status,\n statusCode,\n statusMessage:\n typeof message.statusMessage === \"string\"\n ? message.statusMessage\n : undefined,\n sentAt,\n deliveredAt,\n raw: message,\n });\n } catch (error) {\n return fail(mapSolapiError(error, providerId));\n }\n}\n",
10
8
  "export function isObjectRecord(\n value: unknown,\n): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n",
11
9
  "import { KMsgError, KMsgErrorCode } from \"@k-msg/core\";\nimport {\n ApiKeyError,\n BadRequestError,\n ClientError,\n DefaultError,\n NetworkError,\n ServerError,\n} from \"solapi\";\nimport { isObjectRecord } from \"../shared/type-guards\";\n\nexport function mapSolapiError(error: unknown, providerId: string): KMsgError {\n if (error instanceof KMsgError) return error;\n\n const record = isObjectRecord(error) ? error : {};\n\n if (error instanceof ApiKeyError) {\n return new KMsgError(KMsgErrorCode.AUTHENTICATION_FAILED, error.message, {\n providerId,\n });\n }\n\n if (error instanceof BadRequestError) {\n return new KMsgError(KMsgErrorCode.INVALID_REQUEST, error.message, {\n providerId,\n validationErrors: record.validationErrors,\n });\n }\n\n if (error instanceof NetworkError) {\n return new KMsgError(KMsgErrorCode.NETWORK_ERROR, error.message, {\n providerId,\n url: typeof record.url === \"string\" ? record.url : undefined,\n method: typeof record.method === \"string\" ? record.method : undefined,\n isRetryable:\n typeof record.isRetryable === \"boolean\" ? record.isRetryable : true,\n });\n }\n\n if (error instanceof ClientError) {\n const httpStatus =\n typeof record.httpStatus === \"number\" ? record.httpStatus : undefined;\n const isInvalidRequest =\n typeof httpStatus === \"number\" && httpStatus >= 400 && httpStatus < 500;\n\n return new KMsgError(\n isInvalidRequest\n ? KMsgErrorCode.INVALID_REQUEST\n : KMsgErrorCode.PROVIDER_ERROR,\n error.message,\n {\n providerId,\n httpStatus,\n errorCode: record.errorCode,\n errorMessage: record.errorMessage,\n url: record.url,\n },\n );\n }\n\n if (error instanceof ServerError) {\n return new KMsgError(KMsgErrorCode.PROVIDER_ERROR, error.message, {\n providerId,\n httpStatus:\n typeof record.httpStatus === \"number\" ? record.httpStatus : undefined,\n });\n }\n\n if (error instanceof DefaultError) {\n return new KMsgError(KMsgErrorCode.PROVIDER_ERROR, error.message, {\n providerId,\n errorCode: record.errorCode,\n errorMessage: record.errorMessage,\n });\n }\n\n return new KMsgError(\n KMsgErrorCode.UNKNOWN_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n );\n}\n",
12
10
  "import {\n type DeliveryStatus,\n KMsgError,\n KMsgErrorCode,\n type MessageBinaryInput,\n type MessageButton,\n type MessageVariables,\n type SendOptions,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport type {\n SolapiKakaoButton,\n SolapiMessageType,\n} from \"./solapi.internal.types\";\n\nexport function mapSolapiStatusCode(statusCode?: string): DeliveryStatus {\n if (!statusCode) return \"UNKNOWN\";\n if (statusCode === \"2000\") return \"PENDING\";\n if (statusCode === \"3000\") return \"SENT\";\n if (statusCode === \"4000\") return \"DELIVERED\";\n if (/^[123]\\\\d{3}$/.test(statusCode)) return \"FAILED\";\n return \"UNKNOWN\";\n}\n\nexport function parseDate(value: unknown): Date | undefined {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n return undefined;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return undefined;\n return date;\n}\n\nexport function normalizePhoneNumber(phone: string): string {\n const trimmed = phone.trim();\n if (trimmed.startsWith(\"+\")) {\n return `+${trimmed.slice(1).replace(/\\\\D/g, \"\")}`;\n }\n return trimmed.replace(/\\\\D/g, \"\");\n}\n\nexport function stringifyVariables(\n variables: MessageVariables | undefined,\n): Record<string, string> {\n const output: Record<string, string> = {};\n if (!variables) return output;\n\n for (const [key, value] of Object.entries(variables)) {\n if (value === undefined) continue;\n output[key] =\n value === null\n ? \"\"\n : value instanceof Date\n ? value.toISOString()\n : typeof value === \"string\"\n ? value\n : String(value);\n }\n\n return output;\n}\n\nexport function toKakaoButtons(\n buttons: MessageButton[] | undefined,\n): SolapiKakaoButton[] | undefined {\n if (!Array.isArray(buttons) || buttons.length === 0) return undefined;\n const out: SolapiKakaoButton[] = [];\n\n for (const button of buttons) {\n if (!button) continue;\n if (button.type !== \"WL\") continue;\n if (!button.name || !button.urlMobile) continue;\n out.push({\n buttonName: button.name,\n buttonType: \"WL\",\n linkMo: button.urlMobile,\n linkPc: button.urlPc,\n });\n }\n\n return out.length > 0 ? out : undefined;\n}\n\nexport function resolveImageRef(options: {\n imageUrl?: string;\n media?: { image?: MessageBinaryInput };\n providerId: string;\n}) {\n const imageUrl =\n typeof options.imageUrl === \"string\" && options.imageUrl.trim().length > 0\n ? options.imageUrl.trim()\n : undefined;\n if (imageUrl) return imageUrl;\n\n const image = options.media?.image;\n if (!image) return undefined;\n\n if (\"ref\" in image) {\n const ref = image.ref.trim();\n return ref.length > 0 ? ref : undefined;\n }\n\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"SOLAPI image upload requires `options.imageUrl` or `options.media.image.ref` (url/path).\",\n { providerId: options.providerId },\n );\n}\n\nexport function extractFileId(upload: unknown): string | undefined {\n return isObjectRecord(upload) && typeof upload.fileId === \"string\"\n ? upload.fileId\n : undefined;\n}\n\nexport function toSolapiMessageType(options: SendOptions): SolapiMessageType {\n switch (options.type) {\n case \"ALIMTALK\":\n return \"ATA\";\n case \"FRIENDTALK\":\n return (typeof options.imageUrl === \"string\" &&\n options.imageUrl.trim().length > 0) ||\n Boolean(options.media?.image)\n ? \"CTI\"\n : \"CTA\";\n default:\n return options.type as unknown as SolapiMessageType;\n }\n}\n",
13
- "import {\n type DeliveryStatusQuery,\n type DeliveryStatusResult,\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport { mapSolapiError } from \"./solapi.error\";\nimport { mapSolapiStatusCode, parseDate } from \"./solapi.helpers\";\nimport type { SolapiSdkClient } from \"./solapi.internal.types\";\n\nexport async function getSolapiDeliveryStatus(params: {\n providerId: string;\n client: SolapiSdkClient;\n query: DeliveryStatusQuery;\n}): Promise<Result<DeliveryStatusResult | null, KMsgError>> {\n const { providerId, client, query } = params;\n const providerMessageId = query.providerMessageId.trim();\n if (!providerMessageId) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"providerMessageId is required\",\n { providerId },\n ),\n );\n }\n\n try {\n const response = await client.getMessages({\n messageId: providerMessageId,\n limit: 1,\n });\n\n const record = (isObjectRecord(response) ? response : {}) as Record<\n string,\n unknown\n >;\n const messageList = record.messageList;\n if (\n !messageList ||\n typeof messageList !== \"object\" ||\n Array.isArray(messageList)\n ) {\n return ok(null);\n }\n\n const recordList = messageList as Record<string, unknown>;\n const direct = recordList[providerMessageId];\n\n const values = Object.values(recordList);\n const found = values.find((v) => {\n if (!isObjectRecord(v)) return false;\n const mid = v.messageId;\n return typeof mid === \"string\" ? mid === providerMessageId : false;\n });\n\n const message = isObjectRecord(direct)\n ? direct\n : isObjectRecord(found)\n ? found\n : undefined;\n if (!message) return ok(null);\n\n const statusCode =\n typeof message.statusCode === \"string\" ? message.statusCode : undefined;\n const status = mapSolapiStatusCode(statusCode);\n\n const sentAt = parseDate(message.dateSent);\n const deliveredAt = parseDate(message.dateCompleted);\n\n return ok({\n providerId,\n providerMessageId,\n status,\n statusCode,\n statusMessage:\n typeof message.statusMessage === \"string\"\n ? message.statusMessage\n : undefined,\n sentAt,\n deliveredAt,\n raw: message,\n });\n } catch (error) {\n return fail(mapSolapiError(error, providerId));\n }\n}\n",
14
11
  "import {\n KMsgError,\n KMsgErrorCode,\n type MessageType,\n ok,\n type Result,\n type SendOptions,\n type SendResult,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport {\n extractFileId,\n normalizePhoneNumber,\n resolveImageRef,\n stringifyVariables,\n toKakaoButtons,\n toSolapiMessageType,\n} from \"./solapi.helpers\";\nimport type {\n SolapiSdkClient,\n SolapiSendOneMessage,\n} from \"./solapi.internal.types\";\nimport type { SolapiConfig } from \"./types/solapi\";\n\nexport function collectSolapiSendWarnings(\n options: SendOptions,\n providerId: string,\n): SendResult[\"warnings\"] {\n if (options.type !== \"ALIMTALK\") return undefined;\n if (options.failover?.enabled !== true) return undefined;\n\n return [\n {\n code: \"FAILOVER_PARTIAL_PROVIDER\",\n message:\n \"SOLAPI failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.\",\n details: {\n providerId,\n mappedFields: [\"kakao.disableSms\", \"text\", \"subject\"],\n unsupportedFields: [\"fallbackChannel\"],\n },\n },\n ];\n}\n\nexport function adaptSolapiSendResult(params: {\n options: SendOptions;\n response: unknown;\n providerId: string;\n warnings?: SendResult[\"warnings\"];\n}): SendResult {\n const { options, response, providerId, warnings } = params;\n const record = isObjectRecord(response) ? response : {};\n const providerMessageId =\n typeof record.messageId === \"string\" ? record.messageId : undefined;\n\n return {\n messageId: options.messageId || crypto.randomUUID(),\n providerId,\n providerMessageId,\n status: \"SENT\",\n type: options.type,\n to: options.to,\n ...(Array.isArray(warnings) && warnings.length > 0 ? { warnings } : {}),\n raw: response,\n };\n}\n\nexport async function buildSolapiSendOneMessage(params: {\n options: SendOptions;\n providerId: string;\n config: SolapiConfig;\n client: SolapiSdkClient;\n}): Promise<SolapiSendOneMessage> {\n const { options, providerId, config, client } = params;\n\n const type = toSolapiMessageType(options);\n const scheduledAt = options.options?.scheduledAt;\n const senderNumber =\n typeof options.from === \"string\" && options.from.length > 0\n ? options.from\n : config.defaultFrom;\n\n const base: Record<string, unknown> = {\n to: normalizePhoneNumber(options.to),\n type,\n };\n\n const country =\n typeof options.options?.country === \"string\" &&\n options.options.country.length > 0\n ? options.options.country\n : typeof config.defaultCountry === \"string\"\n ? config.defaultCountry\n : undefined;\n if (country) {\n base.country = country;\n }\n\n const customFieldsRaw = options.options?.customFields;\n if (customFieldsRaw && typeof customFieldsRaw === \"object\") {\n const customFields: Record<string, string> = {};\n for (const [key, value] of Object.entries(customFieldsRaw)) {\n if (value === undefined) continue;\n customFields[key] = typeof value === \"string\" ? value : String(value);\n }\n if (Object.keys(customFields).length > 0) {\n base.customFields = customFields;\n }\n }\n\n if (scheduledAt) {\n base.scheduledDate = scheduledAt;\n }\n\n const requiresFrom =\n type === \"SMS\" ||\n type === \"LMS\" ||\n type === \"MMS\" ||\n type === \"VOICE\" ||\n type === \"FAX\" ||\n String(type).startsWith(\"RCS_\");\n\n if (requiresFrom) {\n if (!senderNumber || senderNumber.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required (options.from or config.defaultFrom)\",\n { providerId, type: options.type as MessageType },\n );\n }\n base.from = normalizePhoneNumber(senderNumber);\n } else if (senderNumber) {\n base.from = normalizePhoneNumber(senderNumber);\n }\n\n if (type === \"SMS\" || type === \"LMS\" || type === \"MMS\") {\n const smsOptions = options as Extract<\n SendOptions,\n { type: \"SMS\" | \"LMS\" | \"MMS\" }\n >;\n const text = smsOptions.text;\n if (text.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for SMS/LMS/MMS\",\n { providerId, type: options.type as MessageType },\n );\n }\n\n base.text = text;\n const subject = smsOptions.subject;\n if (subject) {\n base.subject = subject;\n }\n\n if (type === \"MMS\") {\n const imageRef = resolveImageRef({\n imageUrl: smsOptions.imageUrl,\n media: smsOptions.media,\n providerId,\n });\n if (!imageRef) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"image is required for MMS (options.imageUrl or options.media.image.ref)\",\n { providerId },\n );\n }\n\n const upload = await client.uploadFile(imageRef, \"MMS\");\n const fileId = extractFileId(upload);\n if (typeof fileId === \"string\" && fileId.length > 0) {\n base.imageId = fileId;\n } else {\n throw new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"Failed to upload MMS image\",\n {\n providerId,\n },\n );\n }\n }\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"ATA\") {\n const alimtalkOptions = options as Extract<\n SendOptions,\n { type: \"ALIMTALK\" }\n >;\n const failover = alimtalkOptions.failover;\n const pfId =\n typeof alimtalkOptions.kakao?.profileId === \"string\" &&\n alimtalkOptions.kakao.profileId.length > 0\n ? alimtalkOptions.kakao.profileId\n : config.kakaoPfId;\n\n if (!pfId || pfId.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.kakaoPfId)\",\n { providerId },\n );\n }\n\n const fallbackContent =\n typeof failover?.fallbackContent === \"string\" &&\n failover.fallbackContent.trim().length > 0\n ? failover.fallbackContent.trim()\n : undefined;\n const fallbackTitle =\n typeof failover?.fallbackTitle === \"string\" &&\n failover.fallbackTitle.trim().length > 0\n ? failover.fallbackTitle.trim()\n : undefined;\n const disableSms =\n failover?.enabled === true\n ? false\n : failover?.enabled === false\n ? true\n : alimtalkOptions.kakao?.disableSms;\n\n if (fallbackContent) {\n base.text = fallbackContent;\n }\n if (fallbackTitle) {\n base.subject = fallbackTitle;\n }\n\n base.kakaoOptions = {\n pfId,\n templateId: alimtalkOptions.templateId,\n variables: stringifyVariables(alimtalkOptions.variables),\n disableSms,\n adFlag: alimtalkOptions.kakao?.adFlag,\n buttons: Array.isArray(alimtalkOptions.kakao?.buttons)\n ? alimtalkOptions.kakao.buttons\n : undefined,\n imageId: alimtalkOptions.kakao?.imageId,\n };\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"CTA\" || type === \"CTI\") {\n const friendTalkOptions = options as Extract<\n SendOptions,\n { type: \"FRIENDTALK\" }\n >;\n const text = friendTalkOptions.text;\n if (text.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for FRIENDTALK\",\n { providerId },\n );\n }\n\n const pfId =\n typeof friendTalkOptions.kakao?.profileId === \"string\" &&\n friendTalkOptions.kakao.profileId.length > 0\n ? friendTalkOptions.kakao.profileId\n : config.kakaoPfId;\n\n if (!pfId || pfId.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.kakaoPfId)\",\n { providerId },\n );\n }\n\n const kakaoButtons = toKakaoButtons(friendTalkOptions.buttons);\n const buttons = Array.isArray(friendTalkOptions.kakao?.buttons)\n ? friendTalkOptions.kakao.buttons\n : kakaoButtons;\n\n const imageLinkFromOptions =\n typeof friendTalkOptions.kakao?.imageLink === \"string\" &&\n friendTalkOptions.kakao.imageLink.length > 0\n ? friendTalkOptions.kakao.imageLink\n : undefined;\n const firstButton =\n Array.isArray(buttons) && buttons.length > 0 ? buttons[0] : undefined;\n const imageLinkFromButton =\n isObjectRecord(firstButton) && typeof firstButton.linkMo === \"string\"\n ? (firstButton.linkMo as string)\n : undefined;\n const imageLink = imageLinkFromOptions ?? imageLinkFromButton;\n\n let imageId: string | undefined;\n if (type === \"CTI\") {\n const imageRef = resolveImageRef({\n imageUrl: friendTalkOptions.imageUrl,\n media: friendTalkOptions.media,\n providerId,\n });\n if (!imageRef) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"image is required for CTI (friendtalk image) (options.imageUrl or options.media.image.ref)\",\n { providerId },\n );\n }\n if (!imageLink) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"imageLink is required for friendtalk image upload (options.kakao.imageLink or WL button)\",\n { providerId },\n );\n }\n\n const upload = await client.uploadFile(\n imageRef,\n \"KAKAO\",\n undefined,\n imageLink,\n );\n const fileId = extractFileId(upload);\n if (typeof fileId === \"string\" && fileId.length > 0) {\n imageId = fileId;\n } else {\n throw new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"Failed to upload friendtalk image\",\n {\n providerId,\n },\n );\n }\n }\n\n base.text = text;\n base.kakaoOptions = {\n pfId,\n variables: stringifyVariables(friendTalkOptions.variables),\n disableSms: friendTalkOptions.kakao?.disableSms,\n adFlag: friendTalkOptions.kakao?.adFlag,\n buttons,\n imageId,\n };\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"NSA\") {\n const nsaOptions = options as Extract<SendOptions, { type: \"NSA\" }>;\n const talkId =\n typeof nsaOptions.naver?.talkId === \"string\" &&\n nsaOptions.naver.talkId.length > 0\n ? nsaOptions.naver.talkId\n : config.naverTalkId;\n\n if (!talkId || talkId.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"naver talkId is required (options.naver.talkId or config.naverTalkId)\",\n { providerId },\n );\n }\n\n const templateId =\n typeof nsaOptions.naver?.templateId === \"string\" &&\n nsaOptions.naver.templateId.length > 0\n ? nsaOptions.naver.templateId\n : nsaOptions.templateId;\n\n const variables = {\n ...stringifyVariables(nsaOptions.variables),\n ...stringifyVariables(nsaOptions.naver?.variables),\n };\n\n base.naverOptions = {\n talkId,\n templateId,\n variables,\n disableSms: nsaOptions.naver?.disableSms,\n buttons: Array.isArray(nsaOptions.naver?.buttons)\n ? nsaOptions.naver.buttons\n : undefined,\n };\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"VOICE\") {\n const voiceMessageOptions = options as Extract<\n SendOptions,\n { type: \"VOICE\" }\n >;\n const text = voiceMessageOptions.text;\n if (text.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for VOICE\",\n {\n providerId,\n },\n );\n }\n\n const voiceTypeRaw = voiceMessageOptions.voice?.voiceType;\n const voiceType =\n voiceTypeRaw === \"FEMALE\" || voiceTypeRaw === \"MALE\"\n ? voiceTypeRaw\n : \"FEMALE\";\n\n base.text = text;\n base.voiceOptions = voiceMessageOptions.voice\n ? { ...voiceMessageOptions.voice, voiceType }\n : { voiceType };\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"FAX\") {\n const faxOptions = options as Extract<SendOptions, { type: \"FAX\" }>;\n const fax = faxOptions.fax;\n const fileIdsFromOptions = Array.isArray(fax?.fileIds)\n ? fax.fileIds.filter(\n (value: unknown): value is string =>\n typeof value === \"string\" && value.length > 0,\n )\n : [];\n\n let fileIds = fileIdsFromOptions;\n\n if (fileIds.length === 0) {\n const fileUrls = Array.isArray(fax?.fileUrls)\n ? fax.fileUrls.filter(\n (value: unknown): value is string =>\n typeof value === \"string\" && value.length > 0,\n )\n : [];\n\n if (fileUrls.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"fax.fileIds or fax.fileUrls is required\",\n {\n providerId,\n },\n );\n }\n\n fileIds = [];\n for (const url of fileUrls) {\n const upload = await client.uploadFile(url, \"FAX\");\n const fileId = extractFileId(upload);\n if (typeof fileId === \"string\" && fileId.length > 0) {\n fileIds.push(fileId);\n }\n }\n }\n\n if (fileIds.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"Failed to resolve fax fileIds\",\n {\n providerId,\n },\n );\n }\n\n base.faxOptions = { fileIds };\n return base as unknown as SolapiSendOneMessage;\n }\n\n const rcsOptions = options as Extract<\n SendOptions,\n {\n type:\n | \"RCS_SMS\"\n | \"RCS_LMS\"\n | \"RCS_MMS\"\n | \"RCS_TPL\"\n | \"RCS_ITPL\"\n | \"RCS_LTPL\";\n }\n >;\n const rcs = rcsOptions.rcs;\n\n const brandId =\n typeof rcs?.brandId === \"string\" && rcs.brandId.length > 0\n ? rcs.brandId\n : config.rcsBrandId;\n\n if (!brandId || brandId.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"rcs brandId is required (options.rcs.brandId or config.rcsBrandId)\",\n { providerId },\n );\n }\n\n const rcsPayload: Record<string, unknown> = {\n brandId,\n buttons: Array.isArray(rcs?.buttons) ? rcs.buttons : undefined,\n copyAllowed: rcs?.copyAllowed,\n mmsType: rcs?.mmsType,\n commercialType: rcs?.commercialType,\n disableSms: rcs?.disableSms,\n variables: {\n ...stringifyVariables(rcsOptions.variables),\n ...stringifyVariables(rcs?.variables),\n },\n };\n\n if (type === \"RCS_TPL\" || type === \"RCS_ITPL\" || type === \"RCS_LTPL\") {\n const templateOptions = options as Extract<\n SendOptions,\n { type: \"RCS_TPL\" | \"RCS_ITPL\" | \"RCS_LTPL\" }\n >;\n rcsPayload.templateId =\n typeof templateOptions.rcs?.templateId === \"string\" &&\n templateOptions.rcs.templateId.length > 0\n ? templateOptions.rcs.templateId\n : templateOptions.templateId;\n }\n\n let text: string | undefined;\n let subject: string | undefined;\n if (type === \"RCS_SMS\" || type === \"RCS_LMS\" || type === \"RCS_MMS\") {\n const textOptions = options as Extract<\n SendOptions,\n { type: \"RCS_SMS\" | \"RCS_LMS\" | \"RCS_MMS\" }\n >;\n text = textOptions.text;\n subject = textOptions.subject;\n\n if (!text || text.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for RCS text types\",\n { providerId },\n );\n }\n base.text = text;\n if (subject) base.subject = subject;\n }\n\n const additionalBodyRaw = rcs?.additionalBody;\n const additionalBody = isObjectRecord(additionalBodyRaw)\n ? additionalBodyRaw\n : undefined;\n const additionalBodyImageId =\n additionalBody &&\n typeof additionalBody.imageId === \"string\" &&\n additionalBody.imageId.length > 0\n ? additionalBody.imageId\n : additionalBody &&\n typeof additionalBody.imaggeId === \"string\" &&\n additionalBody.imaggeId.length > 0\n ? additionalBody.imaggeId\n : undefined;\n\n const buildAdditionalBody = (uploadedImageId?: string) => {\n const record = additionalBody ? { ...additionalBody } : {};\n const title =\n typeof record.title === \"string\" && record.title.length > 0\n ? record.title\n : subject || \"RCS\";\n const description =\n typeof record.description === \"string\" && record.description.length > 0\n ? record.description\n : text || \"\";\n const imaggeId = additionalBodyImageId ?? uploadedImageId;\n\n const normalized: Record<string, unknown> = {\n ...record,\n title,\n description,\n };\n\n if (typeof imaggeId === \"string\" && imaggeId.length > 0) {\n normalized.imaggeId = imaggeId;\n }\n\n return normalized;\n };\n\n if (type === \"RCS_MMS\") {\n const rcsTextOptions = options as Extract<\n SendOptions,\n { type: \"RCS_SMS\" | \"RCS_LMS\" | \"RCS_MMS\" }\n >;\n\n const imageRef = resolveImageRef({\n imageUrl: rcsTextOptions.imageUrl,\n media: rcsTextOptions.media,\n providerId,\n });\n if (imageRef) {\n const upload = await client.uploadFile(imageRef, \"RCS\");\n const fileId = extractFileId(upload);\n if (typeof fileId === \"string\" && fileId.length > 0) {\n rcsPayload.additionalBody = buildAdditionalBody(fileId);\n } else if (additionalBody) {\n rcsPayload.additionalBody = buildAdditionalBody(undefined);\n }\n } else if (additionalBody) {\n rcsPayload.additionalBody = buildAdditionalBody(undefined);\n }\n } else if (additionalBody) {\n rcsPayload.additionalBody = buildAdditionalBody(undefined);\n }\n\n base.rcsOptions = rcsPayload;\n return base as unknown as SolapiSendOneMessage;\n}\n\nexport async function sendWithSolapi(params: {\n providerId: string;\n client: SolapiSdkClient;\n config: SolapiConfig;\n options: SendOptions;\n}): Promise<Result<SendResult, KMsgError>> {\n const { providerId, client, config, options } = params;\n\n const warnings = collectSolapiSendWarnings(options, providerId);\n const message = await buildSolapiSendOneMessage({\n options,\n providerId,\n config,\n client,\n });\n const response = await client.sendOne(message, config.appId);\n\n return ok(\n adaptSolapiSendResult({\n options,\n response,\n providerId,\n warnings,\n }),\n );\n}\n"
15
12
  ],
16
- "mappings": "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",
17
- "debugId": "AA25F66A5E1E847664756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "22D7FD78E1A81A5164756E2164756E21",
18
15
  "names": []
19
16
  }
@@ -1,4 +1,4 @@
1
- var oe=Object.defineProperty;var Ie=(e,t)=>{for(var n in t)oe(e,n,{get:t[n],enumerable:!0,configurable:!0,set:(r)=>t[n]=()=>r})};var se={["INVALID_REQUEST"]:{ko:"잘못된 요청입니다",en:"Invalid request"},["AUTHENTICATION_FAILED"]:{ko:"인증에 실패했습니다",en:"Authentication failed"},["INSUFFICIENT_BALANCE"]:{ko:"잔액이 부족합니다",en:"Insufficient balance"},["TEMPLATE_NOT_FOUND"]:{ko:"템플릿을 찾을 수 없습니다",en:"Template not found"},["RATE_LIMIT_EXCEEDED"]:{ko:"요청 한도를 초과했습니다",en:"Rate limit exceeded"},["NETWORK_ERROR"]:{ko:"네트워크 오류가 발생했습니다",en:"Network error"},["NETWORK_TIMEOUT"]:{ko:"네트워크 요청 시간이 초과되었습니다",en:"Network timeout"},["NETWORK_SERVICE_UNAVAILABLE"]:{ko:"서비스를 일시적으로 사용할 수 없습니다",en:"Service temporarily unavailable"},["PROVIDER_ERROR"]:{ko:"제공자 오류가 발생했습니다",en:"Provider error"},["MESSAGE_SEND_FAILED"]:{ko:"메시지 전송에 실패했습니다",en:"Message send failed"},["CRYPTO_CONFIG_ERROR"]:{ko:"암호화 설정 오류가 발생했습니다",en:"Crypto configuration error"},["CRYPTO_ENCRYPT_FAILED"]:{ko:"암호화에 실패했습니다",en:"Encryption failed"},["CRYPTO_DECRYPT_FAILED"]:{ko:"복호화에 실패했습니다",en:"Decryption failed"},["CRYPTO_HASH_FAILED"]:{ko:"해시 생성에 실패했습니다",en:"Hash generation failed"},["CRYPTO_POLICY_VIOLATION"]:{ko:"암호화 정책 위반이 발생했습니다",en:"Crypto policy violation"},["UNKNOWN_ERROR"]:{ko:"알 수 없는 오류가 발생했습니다",en:"Unknown error"}};var V=(e)=>{if(typeof e!=="number"||Number.isNaN(e)||!Number.isFinite(e))return;return Math.trunc(e)};class a extends Error{code;details;providerErrorCode;providerErrorText;httpStatus;requestId;retryAfterMs;attempt;causeChain;constructor(e,t,n,r={}){super(t);if(this.name="KMsgError",this.code=e,this.details=n,this.providerErrorCode=r.providerErrorCode,this.providerErrorText=r.providerErrorText,this.httpStatus=V(r.httpStatus),this.requestId=typeof r.requestId==="string"?r.requestId:void 0,this.retryAfterMs=V(r.retryAfterMs),this.attempt=V(r.attempt),Array.isArray(r.causeChain))this.causeChain=r.causeChain;else if(r.causeChain!==void 0)this.causeChain=[r.causeChain];if(Error.captureStackTrace)Error.captureStackTrace(this,a)}getLocalizedMessage(e="ko"){let t=se[this.code];if(t?.[e])return t[e];return this.message}toJSON(){return{name:this.name,code:this.code,message:this.message,details:this.details,providerErrorCode:this.providerErrorCode,providerErrorText:this.providerErrorText,httpStatus:this.httpStatus,requestId:this.requestId,retryAfterMs:this.retryAfterMs,attempt:this.attempt,causeChain:this.causeChain}}}var C=(e)=>({isSuccess:!0,isFailure:!1,value:e}),K=(e)=>({isSuccess:!1,isFailure:!0,error:e});function de(){let e=globalThis;return e.__K_MSG_ENV__??e.__ENV__??e.process?.env??{}}function k(e){let t=de()[e];if(typeof t==="string")return t;if(t===void 0)return;return String(t)}import{SolapiMessageService as ke}from"solapi";var H={iwinv:{providerId:"iwinv",providerName:"IWINV Messaging Provider",channelOnboarding:"manual",templateLifecycleApi:"available",plusIdPolicy:"optional",plusIdInference:"unsupported",liveTestSupport:"supported",checks:[{id:"channel_registered_in_console",title:"Kakao channel is registered in IWINV console",description:"IWINV channel onboarding is manual. Confirm channel registration and approval in console.",kind:"manual",severity:"blocker",scopes:["doctor","preflight"]},{id:"iwinv_config_required",title:"IWINV config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey"]},{id:"template_capability_available",title:"Template lifecycle APIs are available",kind:"capability",severity:"warning",scopes:["doctor","preflight"],capabilityMethods:["listTemplates","getTemplate","createTemplate","updateTemplate","deleteTemplate"]},{id:"template_list_probe",title:"Template list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_templates"}],notes:["Channel add/auth is not available via IWINV public API in current integration.","Template APIs are available and can be probed."]},aligo:{providerId:"aligo",providerName:"Aligo Smart SMS",channelOnboarding:"api",templateLifecycleApi:"available",plusIdPolicy:"required_if_no_inference",plusIdInference:"supported",liveTestSupport:"supported",checks:[{id:"aligo_config_required",title:"Aligo config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey","userId"]},{id:"channel_api_capability_available",title:"Kakao channel APIs are available",kind:"capability",severity:"warning",scopes:["doctor","preflight"],capabilityMethods:["listKakaoChannels","requestKakaoChannelAuth","addKakaoChannel"]},{id:"channel_list_probe",title:"Kakao channel list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_kakao_channels"},{id:"template_list_probe",title:"Template list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_templates"}]},solapi:{providerId:"solapi",providerName:"SOLAPI Messaging Provider",channelOnboarding:"none",templateLifecycleApi:"unavailable",plusIdPolicy:"required_if_no_inference",plusIdInference:"unsupported",liveTestSupport:"partial",checks:[{id:"solapi_config_required",title:"SOLAPI config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey","apiSecret"]}],notes:["SOLAPI ALIMTALK requires kakao profileId/pfId, but plusId inference is not available in current integration."]},mock:{providerId:"mock",providerName:"Mock Provider",channelOnboarding:"api",templateLifecycleApi:"available",plusIdPolicy:"optional",plusIdInference:"supported",liveTestSupport:"none",checks:[{id:"mock_template_capability_available",title:"Mock template APIs are available",kind:"capability",severity:"info",scopes:["doctor","preflight"],capabilityMethods:["listTemplates","getTemplate","createTemplate"]}]}};function G(e){return H[e]}function Et(){return Object.values(H)}function m(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}import{ApiKeyError as le,BadRequestError as ce,ClientError as fe,DefaultError as ye,NetworkError as ue,ServerError as ge}from"solapi";function O(e,t){if(e instanceof a)return e;let n=m(e)?e:{};if(e instanceof le)return new a("AUTHENTICATION_FAILED",e.message,{providerId:t});if(e instanceof ce)return new a("INVALID_REQUEST",e.message,{providerId:t,validationErrors:n.validationErrors});if(e instanceof ue)return new a("NETWORK_ERROR",e.message,{providerId:t,url:typeof n.url==="string"?n.url:void 0,method:typeof n.method==="string"?n.method:void 0,isRetryable:typeof n.isRetryable==="boolean"?n.isRetryable:!0});if(e instanceof fe){let r=typeof n.httpStatus==="number"?n.httpStatus:void 0,l=typeof r==="number"&&r>=400&&r<500;return new a(l?"INVALID_REQUEST":"PROVIDER_ERROR",e.message,{providerId:t,httpStatus:r,errorCode:n.errorCode,errorMessage:n.errorMessage,url:n.url})}if(e instanceof ge)return new a("PROVIDER_ERROR",e.message,{providerId:t,httpStatus:typeof n.httpStatus==="number"?n.httpStatus:void 0});if(e instanceof ye)return new a("PROVIDER_ERROR",e.message,{providerId:t,errorCode:n.errorCode,errorMessage:n.errorMessage});return new a("UNKNOWN_ERROR",e instanceof Error?e.message:String(e),{providerId:t})}function J(e){if(!e)return"UNKNOWN";if(e==="2000")return"PENDING";if(e==="3000")return"SENT";if(e==="4000")return"DELIVERED";if(/^[123]\\d{3}$/.test(e))return"FAILED";return"UNKNOWN"}function j(e){if(typeof e!=="string"||e.trim().length===0)return;let t=new Date(e);if(Number.isNaN(t.getTime()))return;return t}function N(e){let t=e.trim();if(t.startsWith("+"))return`+${t.slice(1).replace(/\\D/g,"")}`;return t.replace(/\\D/g,"")}function w(e){let t={};if(!e)return t;for(let[n,r]of Object.entries(e)){if(r===void 0)continue;t[n]=r===null?"":r instanceof Date?r.toISOString():typeof r==="string"?r:String(r)}return t}function Y(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e){if(!n)continue;if(n.type!=="WL")continue;if(!n.name||!n.urlMobile)continue;t.push({buttonName:n.name,buttonType:"WL",linkMo:n.urlMobile,linkPc:n.urlPc})}return t.length>0?t:void 0}function L(e){let t=typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0?e.imageUrl.trim():void 0;if(t)return t;let n=e.media?.image;if(!n)return;if("ref"in n){let r=n.ref.trim();return r.length>0?r:void 0}throw new a("INVALID_REQUEST","SOLAPI image upload requires `options.imageUrl` or `options.media.image.ref` (url/path).",{providerId:e.providerId})}function x(e){return m(e)&&typeof e.fileId==="string"?e.fileId:void 0}function X(e){switch(e.type){case"ALIMTALK":return"ATA";case"FRIENDTALK":return typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0||Boolean(e.media?.image)?"CTI":"CTA";default:return e.type}}async function Z(e){let{providerId:t,client:n,query:r}=e,l=r.providerMessageId.trim();if(!l)return K(new a("INVALID_REQUEST","providerMessageId is required",{providerId:t}));try{let o=await n.getMessages({messageId:l,limit:1}),h=(m(o)?o:{}).messageList;if(!h||typeof h!=="object"||Array.isArray(h))return C(null);let p=h,M=p[l],q=Object.values(p).find((R)=>{if(!m(R))return!1;let P=R.messageId;return typeof P==="string"?P===l:!1}),S=m(M)?M:m(q)?q:void 0;if(!S)return C(null);let u=typeof S.statusCode==="string"?S.statusCode:void 0,F=J(u),I=j(S.dateSent),A=j(S.dateCompleted);return C({providerId:t,providerMessageId:l,status:F,statusCode:u,statusMessage:typeof S.statusMessage==="string"?S.statusMessage:void 0,sentAt:I,deliveredAt:A,raw:S})}catch(o){return K(O(o,t))}}function me(e,t){if(e.type!=="ALIMTALK")return;if(e.failover?.enabled!==!0)return;return[{code:"FAILOVER_PARTIAL_PROVIDER",message:"SOLAPI failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.",details:{providerId:t,mappedFields:["kakao.disableSms","text","subject"],unsupportedFields:["fallbackChannel"]}}]}function he(e){let{options:t,response:n,providerId:r,warnings:l}=e,o=m(n)?n:{},b=typeof o.messageId==="string"?o.messageId:void 0;return{messageId:t.messageId||crypto.randomUUID(),providerId:r,providerMessageId:b,status:"SENT",type:t.type,to:t.to,...Array.isArray(l)&&l.length>0?{warnings:l}:{},raw:n}}async function Se(e){let{options:t,providerId:n,config:r,client:l}=e,o=X(t),b=t.options?.scheduledAt,h=typeof t.from==="string"&&t.from.length>0?t.from:r.defaultFrom,p={to:N(t.to),type:o},M=typeof t.options?.country==="string"&&t.options.country.length>0?t.options.country:typeof r.defaultCountry==="string"?r.defaultCountry:void 0;if(M)p.country=M;let _=t.options?.customFields;if(_&&typeof _==="object"){let i={};for(let[s,d]of Object.entries(_)){if(d===void 0)continue;i[s]=typeof d==="string"?d:String(d)}if(Object.keys(i).length>0)p.customFields=i}if(b)p.scheduledDate=b;if(o==="SMS"||o==="LMS"||o==="MMS"||o==="VOICE"||o==="FAX"||String(o).startsWith("RCS_")){if(!h||h.length===0)throw new a("INVALID_REQUEST","from is required (options.from or config.defaultFrom)",{providerId:n,type:t.type});p.from=N(h)}else if(h)p.from=N(h);if(o==="SMS"||o==="LMS"||o==="MMS"){let i=t,s=i.text;if(s.length===0)throw new a("INVALID_REQUEST","text is required for SMS/LMS/MMS",{providerId:n,type:t.type});p.text=s;let d=i.subject;if(d)p.subject=d;if(o==="MMS"){let c=L({imageUrl:i.imageUrl,media:i.media,providerId:n});if(!c)throw new a("INVALID_REQUEST","image is required for MMS (options.imageUrl or options.media.image.ref)",{providerId:n});let f=await l.uploadFile(c,"MMS"),y=x(f);if(typeof y==="string"&&y.length>0)p.imageId=y;else throw new a("PROVIDER_ERROR","Failed to upload MMS image",{providerId:n})}return p}if(o==="ATA"){let i=t,s=i.failover,d=typeof i.kakao?.profileId==="string"&&i.kakao.profileId.length>0?i.kakao.profileId:r.kakaoPfId;if(!d||d.length===0)throw new a("INVALID_REQUEST","kakao profileId is required (options.kakao.profileId or config.kakaoPfId)",{providerId:n});let c=typeof s?.fallbackContent==="string"&&s.fallbackContent.trim().length>0?s.fallbackContent.trim():void 0,f=typeof s?.fallbackTitle==="string"&&s.fallbackTitle.trim().length>0?s.fallbackTitle.trim():void 0,y=s?.enabled===!0?!1:s?.enabled===!1?!0:i.kakao?.disableSms;if(c)p.text=c;if(f)p.subject=f;return p.kakaoOptions={pfId:d,templateId:i.templateId,variables:w(i.variables),disableSms:y,adFlag:i.kakao?.adFlag,buttons:Array.isArray(i.kakao?.buttons)?i.kakao.buttons:void 0,imageId:i.kakao?.imageId},p}if(o==="CTA"||o==="CTI"){let i=t,s=i.text;if(s.length===0)throw new a("INVALID_REQUEST","text is required for FRIENDTALK",{providerId:n});let d=typeof i.kakao?.profileId==="string"&&i.kakao.profileId.length>0?i.kakao.profileId:r.kakaoPfId;if(!d||d.length===0)throw new a("INVALID_REQUEST","kakao profileId is required (options.kakao.profileId or config.kakaoPfId)",{providerId:n});let c=Y(i.buttons),f=Array.isArray(i.kakao?.buttons)?i.kakao.buttons:c,y=typeof i.kakao?.imageLink==="string"&&i.kakao.imageLink.length>0?i.kakao.imageLink:void 0,E=Array.isArray(f)&&f.length>0?f[0]:void 0,T=m(E)&&typeof E.linkMo==="string"?E.linkMo:void 0,Q=y??T,W;if(o==="CTI"){let $=L({imageUrl:i.imageUrl,media:i.media,providerId:n});if(!$)throw new a("INVALID_REQUEST","image is required for CTI (friendtalk image) (options.imageUrl or options.media.image.ref)",{providerId:n});if(!Q)throw new a("INVALID_REQUEST","imageLink is required for friendtalk image upload (options.kakao.imageLink or WL button)",{providerId:n});let re=await l.uploadFile($,"KAKAO",void 0,Q),B=x(re);if(typeof B==="string"&&B.length>0)W=B;else throw new a("PROVIDER_ERROR","Failed to upload friendtalk image",{providerId:n})}return p.text=s,p.kakaoOptions={pfId:d,variables:w(i.variables),disableSms:i.kakao?.disableSms,adFlag:i.kakao?.adFlag,buttons:f,imageId:W},p}if(o==="NSA"){let i=t,s=typeof i.naver?.talkId==="string"&&i.naver.talkId.length>0?i.naver.talkId:r.naverTalkId;if(!s||s.length===0)throw new a("INVALID_REQUEST","naver talkId is required (options.naver.talkId or config.naverTalkId)",{providerId:n});let d=typeof i.naver?.templateId==="string"&&i.naver.templateId.length>0?i.naver.templateId:i.templateId,c={...w(i.variables),...w(i.naver?.variables)};return p.naverOptions={talkId:s,templateId:d,variables:c,disableSms:i.naver?.disableSms,buttons:Array.isArray(i.naver?.buttons)?i.naver.buttons:void 0},p}if(o==="VOICE"){let i=t,s=i.text;if(s.length===0)throw new a("INVALID_REQUEST","text is required for VOICE",{providerId:n});let d=i.voice?.voiceType,c=d==="FEMALE"||d==="MALE"?d:"FEMALE";return p.text=s,p.voiceOptions=i.voice?{...i.voice,voiceType:c}:{voiceType:c},p}if(o==="FAX"){let s=t.fax,c=Array.isArray(s?.fileIds)?s.fileIds.filter((f)=>typeof f==="string"&&f.length>0):[];if(c.length===0){let f=Array.isArray(s?.fileUrls)?s.fileUrls.filter((y)=>typeof y==="string"&&y.length>0):[];if(f.length===0)throw new a("INVALID_REQUEST","fax.fileIds or fax.fileUrls is required",{providerId:n});c=[];for(let y of f){let E=await l.uploadFile(y,"FAX"),T=x(E);if(typeof T==="string"&&T.length>0)c.push(T)}}if(c.length===0)throw new a("PROVIDER_ERROR","Failed to resolve fax fileIds",{providerId:n});return p.faxOptions={fileIds:c},p}let S=t,u=S.rcs,F=typeof u?.brandId==="string"&&u.brandId.length>0?u.brandId:r.rcsBrandId;if(!F||F.length===0)throw new a("INVALID_REQUEST","rcs brandId is required (options.rcs.brandId or config.rcsBrandId)",{providerId:n});let I={brandId:F,buttons:Array.isArray(u?.buttons)?u.buttons:void 0,copyAllowed:u?.copyAllowed,mmsType:u?.mmsType,commercialType:u?.commercialType,disableSms:u?.disableSms,variables:{...w(S.variables),...w(u?.variables)}};if(o==="RCS_TPL"||o==="RCS_ITPL"||o==="RCS_LTPL"){let i=t;I.templateId=typeof i.rcs?.templateId==="string"&&i.rcs.templateId.length>0?i.rcs.templateId:i.templateId}let A,R;if(o==="RCS_SMS"||o==="RCS_LMS"||o==="RCS_MMS"){let i=t;if(A=i.text,R=i.subject,!A||A.length===0)throw new a("INVALID_REQUEST","text is required for RCS text types",{providerId:n});if(p.text=A,R)p.subject=R}let P=u?.additionalBody,g=m(P)?P:void 0,ie=g&&typeof g.imageId==="string"&&g.imageId.length>0?g.imageId:g&&typeof g.imaggeId==="string"&&g.imaggeId.length>0?g.imaggeId:void 0,D=(i)=>{let s=g?{...g}:{},d=typeof s.title==="string"&&s.title.length>0?s.title:R||"RCS",c=typeof s.description==="string"&&s.description.length>0?s.description:A||"",f=ie??i,y={...s,title:d,description:c};if(typeof f==="string"&&f.length>0)y.imaggeId=f;return y};if(o==="RCS_MMS"){let i=t,s=L({imageUrl:i.imageUrl,media:i.media,providerId:n});if(s){let d=await l.uploadFile(s,"RCS"),c=x(d);if(typeof c==="string"&&c.length>0)I.additionalBody=D(c);else if(g)I.additionalBody=D(void 0)}else if(g)I.additionalBody=D(void 0)}else if(g)I.additionalBody=D(void 0);return p.rcsOptions=I,p}async function z(e){let{providerId:t,client:n,config:r,options:l}=e,o=me(l,t),b=await Se({options:l,providerId:t,config:r,client:n}),h=await n.sendOne(b,r.appId);return C(he({options:l,response:h,providerId:t,warnings:o}))}class U{id="solapi";name="SOLAPI Messaging Provider";supportedTypes=["ALIMTALK","FRIENDTALK","SMS","LMS","MMS","NSA","VOICE","FAX","RCS_SMS","RCS_LMS","RCS_MMS","RCS_TPL","RCS_ITPL","RCS_LTPL"];config;client;getOnboardingSpec(){let e=G(this.id);if(!e)throw new a("INVALID_REQUEST",`Onboarding spec missing for provider: ${this.id}`,{providerId:this.id});return e}constructor(e,t){if(!e||typeof e!=="object")throw new a("INVALID_REQUEST","SolapiProvider requires a config object",{providerId:this.id});if(!e.apiKey||e.apiKey.length===0)throw Error("SolapiProvider requires `apiKey`");if(!e.apiSecret||e.apiSecret.length===0)throw Error("SolapiProvider requires `apiSecret`");this.config={...e,baseUrl:typeof e.baseUrl==="string"&&e.baseUrl.length>0?e.baseUrl:"https://api.solapi.com"},this.client=t??new ke(this.config.apiKey,this.config.apiSecret)}async healthCheck(){let e=[],t=Date.now();try{if(!this.config.apiKey)e.push("Missing apiKey");if(!this.config.apiSecret)e.push("Missing apiSecret");if(this.config.baseUrl)try{new URL(this.config.baseUrl)}catch{e.push("Invalid baseUrl")}return{healthy:e.length===0,issues:e,latencyMs:Date.now()-t,data:{provider:this.id,baseUrl:this.config.baseUrl}}}catch(n){return e.push(n instanceof Error?n.message:String(n)),{healthy:!1,issues:e,latencyMs:Date.now()-t}}}async send(e){let t=e.messageId||crypto.randomUUID(),n={...e,messageId:t};try{return await z({providerId:this.id,client:this.client,config:this.config,options:n})}catch(r){return K(O(r,this.id))}}async getDeliveryStatus(e){return Z({providerId:this.id,client:this.client,query:e})}async getBalance(e){try{let t=await this.client.getBalance(),n=t,r=[n.balance,n.point],l=Number.NaN;for(let o of r){if(typeof o==="number"&&Number.isFinite(o)){l=o;break}if(typeof o==="string"){let b=Number(o);if(Number.isFinite(b)){l=b;break}}}if(!Number.isFinite(l))return K(O(Error("Invalid balance response from SOLAPI"),this.id));return C({providerId:this.id,channel:e?.channel,amount:l,currency:"KRW",raw:t})}catch(t){return K(O(t,this.id))}}}var ee=(e)=>new U(e),te=()=>{let e={apiKey:k("SOLAPI_API_KEY")||"",apiSecret:k("SOLAPI_API_SECRET")||"",baseUrl:k("SOLAPI_BASE_URL")||"https://api.solapi.com",defaultFrom:k("SOLAPI_DEFAULT_FROM"),kakaoPfId:k("SOLAPI_KAKAO_PF_ID"),rcsBrandId:k("SOLAPI_RCS_BRAND_ID"),naverTalkId:k("SOLAPI_NAVER_TALK_ID"),appId:k("SOLAPI_APP_ID"),defaultCountry:k("SOLAPI_DEFAULT_COUNTRY"),debug:k("NODE_ENV")==="development"};if(!e.apiKey||!e.apiSecret)throw Error("SOLAPI_API_KEY and SOLAPI_API_SECRET environment variables are required");return ee(e)};class ne{static create(e){return new U(e)}static createDefault(){return te()}}function be(){}export{be as initializeSolapi,ee as createSolapiProvider,te as createDefaultSolapiProvider,ne as SolapiProviderFactory,U as SolapiProvider};
1
+ import{fail as Q,KMsgError as ne,KMsgErrorCode as ie,ok as Me,readRuntimeEnv as h}from"@k-msg/core";import{SolapiMessageService as Ae}from"solapi";var $={iwinv:{providerId:"iwinv",providerName:"IWINV Messaging Provider",channelOnboarding:"manual",templateLifecycleApi:"available",plusIdPolicy:"optional",plusIdInference:"unsupported",liveTestSupport:"supported",checks:[{id:"channel_registered_in_console",title:"Kakao channel is registered in IWINV console",description:"IWINV channel onboarding is manual. Confirm channel registration and approval in console.",kind:"manual",severity:"blocker",scopes:["doctor","preflight"]},{id:"iwinv_config_required",title:"IWINV config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey"]},{id:"template_capability_available",title:"Template lifecycle APIs are available",kind:"capability",severity:"warning",scopes:["doctor","preflight"],capabilityMethods:["listTemplates","getTemplate","createTemplate","updateTemplate","deleteTemplate"]},{id:"template_list_probe",title:"Template list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_templates"}],notes:["Channel add/auth is not available via IWINV public API in current integration.","Template APIs are available and can be probed."]},aligo:{providerId:"aligo",providerName:"Aligo Smart SMS",channelOnboarding:"api",templateLifecycleApi:"available",plusIdPolicy:"required_if_no_inference",plusIdInference:"supported",liveTestSupport:"supported",checks:[{id:"aligo_config_required",title:"Aligo config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey","userId"]},{id:"channel_api_capability_available",title:"Kakao channel APIs are available",kind:"capability",severity:"warning",scopes:["doctor","preflight"],capabilityMethods:["listKakaoChannels","requestKakaoChannelAuth","addKakaoChannel"]},{id:"channel_list_probe",title:"Kakao channel list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_kakao_channels"},{id:"template_list_probe",title:"Template list API probe",kind:"api_probe",severity:"warning",scopes:["doctor","preflight"],probeOperation:"list_templates"}]},solapi:{providerId:"solapi",providerName:"SOLAPI Messaging Provider",channelOnboarding:"none",templateLifecycleApi:"unavailable",plusIdPolicy:"required_if_no_inference",plusIdInference:"unsupported",liveTestSupport:"partial",checks:[{id:"solapi_config_required",title:"SOLAPI config has required keys",kind:"config",severity:"blocker",scopes:["doctor","preflight"],configKeys:["apiKey","apiSecret"]}],notes:["SOLAPI ALIMTALK requires kakao profileId/pfId, but plusId inference is not available in current integration."]},mock:{providerId:"mock",providerName:"Mock Provider",channelOnboarding:"api",templateLifecycleApi:"available",plusIdPolicy:"optional",plusIdInference:"supported",liveTestSupport:"none",checks:[{id:"mock_template_capability_available",title:"Mock template APIs are available",kind:"capability",severity:"info",scopes:["doctor","preflight"],capabilityMethods:["listTemplates","getTemplate","createTemplate"]}]}};function G(e){return $[e]}function ve(){return Object.values($)}import{fail as Z,KMsgError as ye,KMsgErrorCode as Se,ok as j}from"@k-msg/core";function y(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}import{KMsgError as M,KMsgErrorCode as A}from"@k-msg/core";import{ApiKeyError as de,BadRequestError as pe,ClientError as fe,DefaultError as ce,NetworkError as ue,ServerError as ge}from"solapi";function T(e,t){if(e instanceof M)return e;let n=y(e)?e:{};if(e instanceof de)return new M(A.AUTHENTICATION_FAILED,e.message,{providerId:t});if(e instanceof pe)return new M(A.INVALID_REQUEST,e.message,{providerId:t,validationErrors:n.validationErrors});if(e instanceof ue)return new M(A.NETWORK_ERROR,e.message,{providerId:t,url:typeof n.url==="string"?n.url:void 0,method:typeof n.method==="string"?n.method:void 0,isRetryable:typeof n.isRetryable==="boolean"?n.isRetryable:!0});if(e instanceof fe){let a=typeof n.httpStatus==="number"?n.httpStatus:void 0,d=typeof a==="number"&&a>=400&&a<500;return new M(d?A.INVALID_REQUEST:A.PROVIDER_ERROR,e.message,{providerId:t,httpStatus:a,errorCode:n.errorCode,errorMessage:n.errorMessage,url:n.url})}if(e instanceof ge)return new M(A.PROVIDER_ERROR,e.message,{providerId:t,httpStatus:typeof n.httpStatus==="number"?n.httpStatus:void 0});if(e instanceof ce)return new M(A.PROVIDER_ERROR,e.message,{providerId:t,errorCode:n.errorCode,errorMessage:n.errorMessage});return new M(A.UNKNOWN_ERROR,e instanceof Error?e.message:String(e),{providerId:t})}import{KMsgError as me,KMsgErrorCode as Ie}from"@k-msg/core";function H(e){if(!e)return"UNKNOWN";if(e==="2000")return"PENDING";if(e==="3000")return"SENT";if(e==="4000")return"DELIVERED";if(/^[123]\\d{3}$/.test(e))return"FAILED";return"UNKNOWN"}function B(e){if(typeof e!=="string"||e.trim().length===0)return;let t=new Date(e);if(Number.isNaN(t.getTime()))return;return t}function U(e){let t=e.trim();if(t.startsWith("+"))return`+${t.slice(1).replace(/\\D/g,"")}`;return t.replace(/\\D/g,"")}function w(e){let t={};if(!e)return t;for(let[n,a]of Object.entries(e)){if(a===void 0)continue;t[n]=a===null?"":a instanceof Date?a.toISOString():typeof a==="string"?a:String(a)}return t}function J(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e){if(!n)continue;if(n.type!=="WL")continue;if(!n.name||!n.urlMobile)continue;t.push({buttonName:n.name,buttonType:"WL",linkMo:n.urlMobile,linkPc:n.urlPc})}return t.length>0?t:void 0}function F(e){let t=typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0?e.imageUrl.trim():void 0;if(t)return t;let n=e.media?.image;if(!n)return;if("ref"in n){let a=n.ref.trim();return a.length>0?a:void 0}throw new me(Ie.INVALID_REQUEST,"SOLAPI image upload requires `options.imageUrl` or `options.media.image.ref` (url/path).",{providerId:e.providerId})}function P(e){return y(e)&&typeof e.fileId==="string"?e.fileId:void 0}function Y(e){switch(e.type){case"ALIMTALK":return"ATA";case"FRIENDTALK":return typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0||Boolean(e.media?.image)?"CTI":"CTA";default:return e.type}}async function ee(e){let{providerId:t,client:n,query:a}=e,d=a.providerMessageId.trim();if(!d)return Z(new ye(Se.INVALID_REQUEST,"providerMessageId is required",{providerId:t}));try{let r=await n.getMessages({messageId:d,limit:1}),S=(y(r)?r:{}).messageList;if(!S||typeof S!=="object"||Array.isArray(S))return j(null);let s=S,E=s[d],V=Object.values(s).find((v)=>{if(!y(v))return!1;let L=v.messageId;return typeof L==="string"?L===d:!1}),k=y(E)?E:y(V)?V:void 0;if(!k)return j(null);let m=typeof k.statusCode==="string"?k.statusCode:void 0,_=H(m),R=B(k.dateSent),O=B(k.dateCompleted);return j({providerId:t,providerMessageId:d,status:_,statusCode:m,statusMessage:typeof k.statusMessage==="string"?k.statusMessage:void 0,sentAt:R,deliveredAt:O,raw:k})}catch(r){return Z(T(r,t))}}import{KMsgError as c,KMsgErrorCode as u,ok as ke}from"@k-msg/core";function be(e,t){if(e.type!=="ALIMTALK")return;if(e.failover?.enabled!==!0)return;return[{code:"FAILOVER_PARTIAL_PROVIDER",message:"SOLAPI failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.",details:{providerId:t,mappedFields:["kakao.disableSms","text","subject"],unsupportedFields:["fallbackChannel"]}}]}function he(e){let{options:t,response:n,providerId:a,warnings:d}=e,r=y(n)?n:{},b=typeof r.messageId==="string"?r.messageId:void 0;return{messageId:t.messageId||crypto.randomUUID(),providerId:a,providerMessageId:b,status:"SENT",type:t.type,to:t.to,...Array.isArray(d)&&d.length>0?{warnings:d}:{},raw:n}}async function Re(e){let{options:t,providerId:n,config:a,client:d}=e,r=Y(t),b=t.options?.scheduledAt,S=typeof t.from==="string"&&t.from.length>0?t.from:a.defaultFrom,s={to:U(t.to),type:r},E=typeof t.options?.country==="string"&&t.options.country.length>0?t.options.country:typeof a.defaultCountry==="string"?a.defaultCountry:void 0;if(E)s.country=E;let N=t.options?.customFields;if(N&&typeof N==="object"){let i={};for(let[o,l]of Object.entries(N)){if(l===void 0)continue;i[o]=typeof l==="string"?l:String(l)}if(Object.keys(i).length>0)s.customFields=i}if(b)s.scheduledDate=b;if(r==="SMS"||r==="LMS"||r==="MMS"||r==="VOICE"||r==="FAX"||String(r).startsWith("RCS_")){if(!S||S.length===0)throw new c(u.INVALID_REQUEST,"from is required (options.from or config.defaultFrom)",{providerId:n,type:t.type});s.from=U(S)}else if(S)s.from=U(S);if(r==="SMS"||r==="LMS"||r==="MMS"){let i=t,o=i.text;if(o.length===0)throw new c(u.INVALID_REQUEST,"text is required for SMS/LMS/MMS",{providerId:n,type:t.type});s.text=o;let l=i.subject;if(l)s.subject=l;if(r==="MMS"){let p=F({imageUrl:i.imageUrl,media:i.media,providerId:n});if(!p)throw new c(u.INVALID_REQUEST,"image is required for MMS (options.imageUrl or options.media.image.ref)",{providerId:n});let f=await d.uploadFile(p,"MMS"),g=P(f);if(typeof g==="string"&&g.length>0)s.imageId=g;else throw new c(u.PROVIDER_ERROR,"Failed to upload MMS image",{providerId:n})}return s}if(r==="ATA"){let i=t,o=i.failover,l=typeof i.kakao?.profileId==="string"&&i.kakao.profileId.length>0?i.kakao.profileId:a.kakaoPfId;if(!l||l.length===0)throw new c(u.INVALID_REQUEST,"kakao profileId is required (options.kakao.profileId or config.kakaoPfId)",{providerId:n});let p=typeof o?.fallbackContent==="string"&&o.fallbackContent.trim().length>0?o.fallbackContent.trim():void 0,f=typeof o?.fallbackTitle==="string"&&o.fallbackTitle.trim().length>0?o.fallbackTitle.trim():void 0,g=o?.enabled===!0?!1:o?.enabled===!1?!0:i.kakao?.disableSms;if(p)s.text=p;if(f)s.subject=f;return s.kakaoOptions={pfId:l,templateId:i.templateId,variables:w(i.variables),disableSms:g,adFlag:i.kakao?.adFlag,buttons:Array.isArray(i.kakao?.buttons)?i.kakao.buttons:void 0,imageId:i.kakao?.imageId},s}if(r==="CTA"||r==="CTI"){let i=t,o=i.text;if(o.length===0)throw new c(u.INVALID_REQUEST,"text is required for FRIENDTALK",{providerId:n});let l=typeof i.kakao?.profileId==="string"&&i.kakao.profileId.length>0?i.kakao.profileId:a.kakaoPfId;if(!l||l.length===0)throw new c(u.INVALID_REQUEST,"kakao profileId is required (options.kakao.profileId or config.kakaoPfId)",{providerId:n});let p=J(i.buttons),f=Array.isArray(i.kakao?.buttons)?i.kakao.buttons:p,g=typeof i.kakao?.imageLink==="string"&&i.kakao.imageLink.length>0?i.kakao.imageLink:void 0,C=Array.isArray(f)&&f.length>0?f[0]:void 0,x=y(C)&&typeof C.linkMo==="string"?C.linkMo:void 0,W=g??x,X;if(r==="CTI"){let z=F({imageUrl:i.imageUrl,media:i.media,providerId:n});if(!z)throw new c(u.INVALID_REQUEST,"image is required for CTI (friendtalk image) (options.imageUrl or options.media.image.ref)",{providerId:n});if(!W)throw new c(u.INVALID_REQUEST,"imageLink is required for friendtalk image upload (options.kakao.imageLink or WL button)",{providerId:n});let le=await d.uploadFile(z,"KAKAO",void 0,W),q=P(le);if(typeof q==="string"&&q.length>0)X=q;else throw new c(u.PROVIDER_ERROR,"Failed to upload friendtalk image",{providerId:n})}return s.text=o,s.kakaoOptions={pfId:l,variables:w(i.variables),disableSms:i.kakao?.disableSms,adFlag:i.kakao?.adFlag,buttons:f,imageId:X},s}if(r==="NSA"){let i=t,o=typeof i.naver?.talkId==="string"&&i.naver.talkId.length>0?i.naver.talkId:a.naverTalkId;if(!o||o.length===0)throw new c(u.INVALID_REQUEST,"naver talkId is required (options.naver.talkId or config.naverTalkId)",{providerId:n});let l=typeof i.naver?.templateId==="string"&&i.naver.templateId.length>0?i.naver.templateId:i.templateId,p={...w(i.variables),...w(i.naver?.variables)};return s.naverOptions={talkId:o,templateId:l,variables:p,disableSms:i.naver?.disableSms,buttons:Array.isArray(i.naver?.buttons)?i.naver.buttons:void 0},s}if(r==="VOICE"){let i=t,o=i.text;if(o.length===0)throw new c(u.INVALID_REQUEST,"text is required for VOICE",{providerId:n});let l=i.voice?.voiceType,p=l==="FEMALE"||l==="MALE"?l:"FEMALE";return s.text=o,s.voiceOptions=i.voice?{...i.voice,voiceType:p}:{voiceType:p},s}if(r==="FAX"){let o=t.fax,p=Array.isArray(o?.fileIds)?o.fileIds.filter((f)=>typeof f==="string"&&f.length>0):[];if(p.length===0){let f=Array.isArray(o?.fileUrls)?o.fileUrls.filter((g)=>typeof g==="string"&&g.length>0):[];if(f.length===0)throw new c(u.INVALID_REQUEST,"fax.fileIds or fax.fileUrls is required",{providerId:n});p=[];for(let g of f){let C=await d.uploadFile(g,"FAX"),x=P(C);if(typeof x==="string"&&x.length>0)p.push(x)}}if(p.length===0)throw new c(u.PROVIDER_ERROR,"Failed to resolve fax fileIds",{providerId:n});return s.faxOptions={fileIds:p},s}let k=t,m=k.rcs,_=typeof m?.brandId==="string"&&m.brandId.length>0?m.brandId:a.rcsBrandId;if(!_||_.length===0)throw new c(u.INVALID_REQUEST,"rcs brandId is required (options.rcs.brandId or config.rcsBrandId)",{providerId:n});let R={brandId:_,buttons:Array.isArray(m?.buttons)?m.buttons:void 0,copyAllowed:m?.copyAllowed,mmsType:m?.mmsType,commercialType:m?.commercialType,disableSms:m?.disableSms,variables:{...w(k.variables),...w(m?.variables)}};if(r==="RCS_TPL"||r==="RCS_ITPL"||r==="RCS_LTPL"){let i=t;R.templateId=typeof i.rcs?.templateId==="string"&&i.rcs.templateId.length>0?i.rcs.templateId:i.templateId}let O,v;if(r==="RCS_SMS"||r==="RCS_LMS"||r==="RCS_MMS"){let i=t;if(O=i.text,v=i.subject,!O||O.length===0)throw new c(u.INVALID_REQUEST,"text is required for RCS text types",{providerId:n});if(s.text=O,v)s.subject=v}let L=m?.additionalBody,I=y(L)?L:void 0,se=I&&typeof I.imageId==="string"&&I.imageId.length>0?I.imageId:I&&typeof I.imaggeId==="string"&&I.imaggeId.length>0?I.imaggeId:void 0,D=(i)=>{let o=I?{...I}:{},l=typeof o.title==="string"&&o.title.length>0?o.title:v||"RCS",p=typeof o.description==="string"&&o.description.length>0?o.description:O||"",f=se??i,g={...o,title:l,description:p};if(typeof f==="string"&&f.length>0)g.imaggeId=f;return g};if(r==="RCS_MMS"){let i=t,o=F({imageUrl:i.imageUrl,media:i.media,providerId:n});if(o){let l=await d.uploadFile(o,"RCS"),p=P(l);if(typeof p==="string"&&p.length>0)R.additionalBody=D(p);else if(I)R.additionalBody=D(void 0)}else if(I)R.additionalBody=D(void 0)}else if(I)R.additionalBody=D(void 0);return s.rcsOptions=R,s}async function te(e){let{providerId:t,client:n,config:a,options:d}=e,r=be(d,t),b=await Re({options:d,providerId:t,config:a,client:n}),S=await n.sendOne(b,a.appId);return ke(he({options:d,response:S,providerId:t,warnings:r}))}class K{id="solapi";name="SOLAPI Messaging Provider";supportedTypes=["ALIMTALK","FRIENDTALK","SMS","LMS","MMS","NSA","VOICE","FAX","RCS_SMS","RCS_LMS","RCS_MMS","RCS_TPL","RCS_ITPL","RCS_LTPL"];config;client;getOnboardingSpec(){let e=G(this.id);if(!e)throw new ne(ie.INVALID_REQUEST,`Onboarding spec missing for provider: ${this.id}`,{providerId:this.id});return e}constructor(e,t){if(!e||typeof e!=="object")throw new ne(ie.INVALID_REQUEST,"SolapiProvider requires a config object",{providerId:this.id});if(!e.apiKey||e.apiKey.length===0)throw Error("SolapiProvider requires `apiKey`");if(!e.apiSecret||e.apiSecret.length===0)throw Error("SolapiProvider requires `apiSecret`");this.config={...e,baseUrl:typeof e.baseUrl==="string"&&e.baseUrl.length>0?e.baseUrl:"https://api.solapi.com"},this.client=t??new Ae(this.config.apiKey,this.config.apiSecret)}async healthCheck(){let e=[],t=Date.now();try{if(!this.config.apiKey)e.push("Missing apiKey");if(!this.config.apiSecret)e.push("Missing apiSecret");if(this.config.baseUrl)try{new URL(this.config.baseUrl)}catch{e.push("Invalid baseUrl")}return{healthy:e.length===0,issues:e,latencyMs:Date.now()-t,data:{provider:this.id,baseUrl:this.config.baseUrl}}}catch(n){return e.push(n instanceof Error?n.message:String(n)),{healthy:!1,issues:e,latencyMs:Date.now()-t}}}async send(e){let t=e.messageId||crypto.randomUUID(),n={...e,messageId:t};try{return await te({providerId:this.id,client:this.client,config:this.config,options:n})}catch(a){return Q(T(a,this.id))}}async getDeliveryStatus(e){return ee({providerId:this.id,client:this.client,query:e})}async getBalance(e){try{let t=await this.client.getBalance(),n=t,a=[n.balance,n.point],d=Number.NaN;for(let r of a){if(typeof r==="number"&&Number.isFinite(r)){d=r;break}if(typeof r==="string"){let b=Number(r);if(Number.isFinite(b)){d=b;break}}}if(!Number.isFinite(d))return Q(T(Error("Invalid balance response from SOLAPI"),this.id));return Me({providerId:this.id,channel:e?.channel,amount:d,currency:"KRW",raw:t})}catch(t){return Q(T(t,this.id))}}}var re=(e)=>new K(e),oe=()=>{let e={apiKey:h("SOLAPI_API_KEY")||"",apiSecret:h("SOLAPI_API_SECRET")||"",baseUrl:h("SOLAPI_BASE_URL")||"https://api.solapi.com",defaultFrom:h("SOLAPI_DEFAULT_FROM"),kakaoPfId:h("SOLAPI_KAKAO_PF_ID"),rcsBrandId:h("SOLAPI_RCS_BRAND_ID"),naverTalkId:h("SOLAPI_NAVER_TALK_ID"),appId:h("SOLAPI_APP_ID"),defaultCountry:h("SOLAPI_DEFAULT_COUNTRY"),debug:h("NODE_ENV")==="development"};if(!e.apiKey||!e.apiSecret)throw Error("SOLAPI_API_KEY and SOLAPI_API_SECRET environment variables are required");return re(e)};class ae{static create(e){return new K(e)}static createDefault(){return oe()}}function Oe(){}export{Oe as initializeSolapi,re as createSolapiProvider,oe as createDefaultSolapiProvider,ae as SolapiProviderFactory,K as SolapiProvider};
2
2
 
3
- //# debugId=4B26875CADF2F46E64756E2164756E21
3
+ //# debugId=4D59987D42BF62D264756E2164756E21
4
4
  //# sourceMappingURL=index.mjs.map