@k-msg/provider
Version:
Complete provider system with adapters and implementations for K-Message platform
5 lines (3 loc) • 34.2 kB
JavaScript
import{fail as E,KMsgError as A,KMsgErrorCode as U,ok as ce}from"@k-msg/core";import{validateTemplatePayload as ke}from"@k-msg/template/send";function D(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function P(e){if(!e)return{};try{return JSON.parse(e)}catch{return e}}function Y(e,t){return D(e)?e:t}import{KMsgErrorCode as J}from"@k-msg/core";function tt(e){let t="",n=0;while(n<e.length){let r=e[n++]??0,o=e[n++]??0,i=e[n++]??0,p=r<<16|o<<8|i;t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[p>>18&63],t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[p>>12&63],t+=n-2<e.length?"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[p>>6&63]:"=",t+=n-1<e.length?"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[p&63]:"="}return t}function de(e){return tt(new TextEncoder().encode(e))}function xe(e){let t=e.sendEndpoint||"/api/v2/send/";return t.startsWith("/")?t:`/${t}`}function M(e){let n={AUTH:de(e.apiKey),"Content-Type":"application/json;charset=UTF-8"};if(typeof e.xForwardedFor==="string"&&e.xForwardedFor.length>0)n["X-Forwarded-For"]=e.xForwardedFor;if(e.extraHeaders&&typeof e.extraHeaders==="object")return{...n,...e.extraHeaders};return n}function V(e){switch(e){case 201:case 206:case 401:case 403:return J.AUTHENTICATION_FAILED;case 429:return J.RATE_LIMIT_EXCEEDED;case 519:return J.INSUFFICIENT_BALANCE;case 404:case 501:return J.TEMPLATE_NOT_FOUND;case 502:case 503:case 504:case 505:case 506:case 507:case 508:case 509:case 510:case 511:case 512:case 513:case 514:case 515:case 516:case 517:case 540:return J.INVALID_REQUEST;case 518:return J.PROVIDER_ERROR;default:if(e>=500)return J.PROVIDER_ERROR;return J.INVALID_REQUEST}}function L(e){if(typeof e==="number"&&Number.isFinite(e))return e;if(typeof e==="string"){let t=e.trim();if(t.length===0)return;let n=Number(t);if(Number.isFinite(n))return n}return}function Oe(e){if(typeof e!=="string")return;let t=e.trim().toUpperCase();if(!t)return;switch(t){case"Y":case"APPROVED":return"Y";case"I":case"INSPECTION":return"I";case"R":case"REJECTED":return"R";case"PENDING":return"I";default:return}}function be(e){switch(typeof e==="string"?e.trim().toUpperCase():""){case"Y":return"APPROVED";case"I":return"INSPECTION";case"R":return"REJECTED";default:return"PENDING"}}function Se(e,t){return new Date(e.getTime()+t*24*60*60*1000)}function Ne(e){let t=(n)=>n.toString().padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`}function te(e){if(typeof e!=="string")return;let t=e.trim();if(!t)return;let n=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/.exec(t);if(!n)return;let r=Number(n[1]),o=Number(n[2]),i=Number(n[3]),p=Number(n[4]),a=Number(n[5]),s=Number(n[6]);if(!Number.isFinite(r)||!Number.isFinite(o)||!Number.isFinite(i)||!Number.isFinite(p)||!Number.isFinite(a)||!Number.isFinite(s))return;let c=new Date(r,o-1,i,p,a,s);if(Number.isNaN(c.getTime()))return;return c}function pe(e){let t=(n)=>n.toString().padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())} ${t(e.getHours())}:${t(e.getMinutes())}:${t(e.getSeconds())}`}function Te(e){let t=(n)=>n.toString().padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())} ${t(e.getHours())}:${t(e.getMinutes())}:${t(e.getSeconds())}`}async function ue(e){let t=await e.text(),n=P(t);return Y(n,{code:L(n)??e.status,message:t||String(n||"")})}function _e(e,t){return new A(e.code,e.message,{providerId:t,...e.details??{}})}async function Pe(e){let{providerId:t,config:n,input:r}=e;if(!r||typeof r!=="object")return E(new A(U.INVALID_REQUEST,"Template input is required",{providerId:t}));let o=ke(r,{requireName:!0,requireContent:!0});if(o.isFailure)return E(_e(o.error,t));let i=`${n.baseUrl}/api/template/add/`,p={templateName:o.value.name??r.name,templateContent:o.value.content??r.content,...o.value.buttons?{buttons:o.value.buttons}:{}};try{let a=await fetch(i,{method:"POST",headers:M(n),body:JSON.stringify(p)}),s=await ue(a),c=L(s.code)??a.status,m=typeof s.message==="string"&&s.message.length>0?s.message:"IWINV template create failed";if(!a.ok||c!==200)return E(new A(V(c),m,{providerId:t,originalCode:c}));let f=s.templateCode,y=typeof f==="string"&&f.trim().length>0?f.trim():"";if(!y)return E(new A(U.PROVIDER_ERROR,"IWINV template create did not return templateCode",{providerId:t,raw:s}));let d=new Date;return ce({id:y,code:y,name:o.value.name??r.name,content:o.value.content??r.content,category:r.category,status:"INSPECTION",buttons:o.value.buttons,variables:r.variables,createdAt:d,updatedAt:d})}catch(a){return E(new A(U.NETWORK_ERROR,a instanceof Error?a.message:String(a),{providerId:t}))}}async function Me(e){let{providerId:t,config:n,code:r,patch:o,ctx:i}=e,p=typeof r==="string"?r.trim():"";if(!p)return E(new A(U.INVALID_REQUEST,"code is required",{providerId:t}));let a=await me({providerId:t,config:n,code:p,ctx:i});if(a.isFailure)return a;let s=a.value,c=typeof o.name==="string"&&o.name.trim().length>0?o.name.trim():s.name,m=typeof o.content==="string"&&o.content.trim().length>0?o.content:s.content,f=o.buttons!==void 0?o.buttons:s.buttons,y=ke({name:c,content:m,buttons:f},{requireName:!0,requireContent:!0});if(y.isFailure)return E(_e(y.error,t));let d=`${n.baseUrl}/api/template/modify/`,I={templateCode:p,templateName:y.value.name??c,templateContent:y.value.content??m,...y.value.buttons?{buttons:y.value.buttons}:{}};try{let b=await fetch(d,{method:"POST",headers:M(n),body:JSON.stringify(I)}),u=await ue(b),S=L(u.code)??b.status,v=typeof u.message==="string"&&u.message.length>0?u.message:"IWINV template update failed";if(!b.ok||S!==200)return E(new A(V(S),v,{providerId:t,originalCode:S}));let l=await me({providerId:t,config:n,code:p,ctx:i});if(l.isSuccess)return l;return ce({...s,name:y.value.name??c,content:y.value.content??m,...o.category!==void 0?{category:o.category}:{},...o.variables!==void 0?{variables:o.variables}:{},...o.buttons!==void 0?{buttons:y.value.buttons}:{},updatedAt:new Date})}catch(b){return E(new A(U.NETWORK_ERROR,b instanceof Error?b.message:String(b),{providerId:t}))}}async function Ve(e){let{providerId:t,config:n,code:r}=e,o=typeof r==="string"?r.trim():"";if(!o)return E(new A(U.INVALID_REQUEST,"code is required",{providerId:t}));let i=`${n.baseUrl}/api/template/delete/`,p={templateCode:o};try{let a=await fetch(i,{method:"POST",headers:M(n),body:JSON.stringify(p)}),s=await ue(a),c=L(s.code)??a.status,m=typeof s.message==="string"&&s.message.length>0?s.message:typeof s.messgae==="string"&&s.messgae.length>0?s.messgae:"IWINV template delete failed";if(!a.ok||c!==200)return E(new A(V(c),m,{providerId:t,originalCode:c}));return ce(void 0)}catch(a){return E(new A(U.NETWORK_ERROR,a instanceof Error?a.message:String(a),{providerId:t}))}}async function me(e){let{providerId:t,config:n,code:r}=e,o=typeof r==="string"?r.trim():"";if(!o)return E(new A(U.INVALID_REQUEST,"code is required",{providerId:t}));let i={pageNum:"1",pageSize:"15",templateCode:o},p=`${n.baseUrl}/api/template/`;try{let a=await fetch(p,{method:"POST",headers:M(n),body:JSON.stringify(i)}),s=await ue(a),c=L(s.code)??a.status,m=typeof s.message==="string"&&s.message.length>0?s.message:"IWINV template get failed";if(!a.ok||c!==200)return E(new A(V(c),m,{providerId:t,originalCode:c}));let f=s.list,d=(Array.isArray(f)?f:[]).find(D);if(!d)return E(new A(U.TEMPLATE_NOT_FOUND,"Template not found",{providerId:t,templateCode:o}));let I=d.templateCode,b=typeof I==="string"?I:String(I??""),u=typeof d.templateName==="string"?d.templateName:"",S=typeof d.templateContent==="string"?d.templateContent:"",v=be(d.status),l=te(d.createDate)??new Date;return ce({id:b,code:b,name:u,content:S,status:v,buttons:Array.isArray(d.buttons)?d.buttons:void 0,createdAt:l,updatedAt:l})}catch(a){return E(new A(U.NETWORK_ERROR,a instanceof Error?a.message:String(a),{providerId:t}))}}async function Fe(e){let{providerId:t,config:n,query:r}=e,o=typeof r?.page==="number"&&r.page>0?Math.floor(r.page):1,i=typeof r?.limit==="number"&&r.limit>0?Math.floor(r.limit):15,p=Oe(r?.status),a={pageNum:String(o),pageSize:String(i),...p?{templateStatus:p}:{}},s=`${n.baseUrl}/api/template/`;try{let c=await fetch(s,{method:"POST",headers:M(n),body:JSON.stringify(a)}),m=await ue(c),f=L(m.code)??c.status,y=typeof m.message==="string"&&m.message.length>0?m.message:"IWINV template list failed";if(!c.ok||f!==200)return E(new A(V(f),y,{providerId:t,originalCode:f}));let d=m.list,b=(Array.isArray(d)?d:[]).filter(D).map((u)=>{let S=u.templateCode,v=typeof S==="string"?S:String(S??""),l=typeof u.templateName==="string"?u.templateName:"",h=typeof u.templateContent==="string"?u.templateContent:"",N=be(u.status),g=te(u.createDate)??new Date;return{id:v,code:v,name:l,content:h,status:N,buttons:Array.isArray(u.buttons)?u.buttons:void 0,createdAt:g,updatedAt:g}}).filter((u)=>u.code.length>0);return ce(b)}catch(c){return E(new A(U.NETWORK_ERROR,c instanceof Error?c.message:String(c),{providerId:t}))}}import{fail as H,KMsgError as O,KMsgErrorCode as _,ok as et,readRuntimeEnv as $}from"@k-msg/core";var Le={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 Ue(e){return Le[e]}function At(){return Object.values(Le)}var qe="https://alimtalk.bizservice.iwinv.kr",Ke="https://sms.bizservice.iwinv.kr";import{fail as q,KMsgError as W,KMsgErrorCode as Z,ok as se}from"@k-msg/core";import{KMsgError as fe,KMsgErrorCode as ge}from"@k-msg/core";function nt(e){if(typeof DOMException<"u"&&e instanceof DOMException&&e.name==="TimeoutError")return!0;return typeof e==="object"&&e!==null&&"code"in e&&e.code===ge.NETWORK_TIMEOUT}function rt(e){return typeof DOMException<"u"&&e instanceof DOMException&&e.name==="AbortError"}function ot(e){if(e instanceof Error)return e.message;if(typeof e==="string"&&e.length>0)return e;return"Provider request aborted"}function st(e,t,n){if(!t?.aborted)return;if(e instanceof fe)return e;let r=t.reason??e,o=rt(r)?e:r;return new fe(nt(r)?ge.NETWORK_TIMEOUT:ge.REQUEST_ABORTED,ot(o),{providerId:n})}function ye(e,t){if(e instanceof fe)return e;return new fe(ge.NETWORK_ERROR,e instanceof Error?e.message:String(e),{providerId:t})}function G(e,t,n){return st(e,t,n)??ye(e,n)}async function ne(e,t,n,r){let o=e?.fetch??globalThis.fetch;if(typeof o!=="function")throw ye(Error("No fetch implementation is available; provide ProviderRequestContext.fetch or use a runtime with native fetch support"),r);try{return await o(t,{...n,signal:e?.signal})}catch(i){throw G(i,e?.signal,r)}}import{KMsgErrorCode as le}from"@k-msg/core";function B(e){return e.replace(/[^0-9]/g,"")}function Q(){return Ke}function X(e){if(e.smsApiKey&&e.smsAuthKey)return de(`${e.smsApiKey}&${e.smsAuthKey}`);let t=e.smsAuthKey||e.smsApiKey;if(!t)return"";return de(`${e.apiKey}&${t}`)}function re(e){return X(e).length>0}function we(e){if(typeof e==="number"&&Number.isFinite(e))return e.toString();if(typeof e==="string")return e.trim();return""}function ve(e,t){return{"0":"전송 성공","1":"메시지가 전송되지 않았습니다.","11":"운영 중인 서비스가 아닙니다.","12":"요금제 충전 중입니다. 잠시 후 다시 시도해 보시기 바랍니다.","13":"등록되지 않은 발신번호입니다.","14":"인증 요청이 올바르지 않습니다.","15":"등록하지 않은 IP에서는 발송되지 않습니다.","21":"장문 메시지는 2000 Bytes까지만 입력이 가능합니다.","22":"제목 입력 가능 문자가 올바르지 않습니다.","23":"제목은 40 Byte까지만 입력이 가능합니다.","31":"파일 업로드는 100KB까지 가능합니다.","32":"허용되지 않는 파일 확장자입니다.","33":"이미지 업로드에 실패했습니다.","41":"수신 번호를 입력하여 주세요.","42":"예약 전송 가능 시간이 아닙니다.","43":"날짜와 시간 표현 형식에 맞춰 입력하여 주십시오.","44":"최대 1000건 전송 가능합니다.","50":"SMS 자동 충전 한도를 초과하였습니다.","202":"SMS API 인증 실패 또는 SMS 서비스 권한이 없습니다.","206":"등록하지 않은 IP에서는 발송되지 않습니다."}[e]||t}function he(e,t){if(e==="14"||e==="15"||e==="202"||e==="206")return le.AUTHENTICATION_FAILED;if(e==="50")return le.INSUFFICIENT_BALANCE;if(e==="13"||e==="21"||e==="22"||e==="23"||e==="31"||e==="32"||e==="33"||e==="41"||e==="42"||e==="43"||e==="44")return le.INVALID_REQUEST;if(!t)return le.NETWORK_ERROR;return le.PROVIDER_ERROR}function Ee(e,t){if(t&&t.trim().length>0)return t.trim();return e.slice(0,20)}function ze(e,t){if(e==="06")return"DELIVERED";if(e==="1000")return"DELIVERED";if(typeof t==="string"){if(t.includes("전송 성공"))return"DELIVERED";if(t.includes("대기")||t.includes("처리중"))return"PENDING"}if(e==="00"||e==="01")return"PENDING";if(!e&&!t)return"UNKNOWN";return"FAILED"}async function He(e){let{providerId:t,config:n,query:r,context:o}=e,i=r.providerMessageId.trim();if(!i)return q(new W(Z.INVALID_REQUEST,"providerMessageId is required",{providerId:t}));let p=B(r.to);if(!p)return q(new W(Z.INVALID_REQUEST,"to is required",{providerId:t}));let a=Number(i),s=Number.isFinite(a)?a:void 0,c=pe(Se(r.requestedAt,-1)),m=pe(new Date),f={pageNum:1,pageSize:15,phone:p,startDate:c,endDate:m,...s!==void 0?{seqNo:s}:{},...r.scheduledAt instanceof Date&&!Number.isNaN(r.scheduledAt.getTime())?{reserve:"Y"}:{}},y=`${n.baseUrl}/api/history/`;try{let d=await ne(o,y,{method:"POST",headers:M(n),body:JSON.stringify(f)},t),I=await d.text(),b=P(I),u=Y(b,{}),S=u.code,v=typeof S==="number"?S:void 0,l=typeof u.message==="string"&&u.message.length>0?u.message:"IWINV history query failed";if(!d.ok||v!==200)return q(new W(V(v??L(b)??d.status),l,{providerId:t,originalCode:S??d.status}));let h=u.list,N=Array.isArray(h)?h:[];if(N.length===0)return se(null);let g=(()=>{if(s===void 0)return N[0];return N.find((w)=>D(w)&&w.seqNo===s)??N[0]})();if(!D(g))return se(null);let k=typeof g.statusCode==="string"?g.statusCode:void 0,C=typeof g.statusCodeName==="string"?g.statusCodeName:void 0,T=te(g.sendDate),j=te(g.receiveDate),z=k==="OK"||typeof C==="string"&&C.includes("성공");return se({providerId:t,providerMessageId:i,status:z?"DELIVERED":T?"FAILED":"PENDING",statusCode:k,statusMessage:C,sentAt:T,deliveredAt:z?j||T:void 0,failedAt:!z&&T?T:void 0,raw:g})}catch(d){return q(G(d,o?.signal,t))}}async function $e(e){let{providerId:t,config:n,query:r,context:o}=e;if(!re(n))return q(new W(Z.INVALID_REQUEST,"SMS v2 configuration missing (smsApiKey/smsAuthKey)",{providerId:t}));if(!n.smsCompanyId||n.smsCompanyId.length===0)return q(new W(Z.INVALID_REQUEST,"smsCompanyId required for history (config.smsCompanyId)",{providerId:t}));let i=r.providerMessageId.trim();if(!i)return q(new W(Z.INVALID_REQUEST,"providerMessageId is required",{providerId:t}));let p=B(r.to);if(!p)return q(new W(Z.INVALID_REQUEST,"to is required",{providerId:t}));let a=Se(r.requestedAt,-1),s=new Date;if(s.getTime()-a.getTime()>7776000000)return q(new W(Z.INVALID_REQUEST,"SMS history date range must be within 90 days",{providerId:t}));let f={version:"1.0",companyid:n.smsCompanyId,startDate:Ne(a),endDate:Ne(s),requestNo:i,pageNum:1,pageSize:15,phone:p},d={"Content-Type":"application/json;charset=UTF-8",secret:X(n)};if(typeof n.xForwardedFor==="string"&&n.xForwardedFor.length>0)d["X-Forwarded-For"]=n.xForwardedFor;let I=n.extraHeaders&&typeof n.extraHeaders==="object"?{...d,...n.extraHeaders}:d,b=`${Q()}/api/history/`;try{let u=await ne(o,b,{method:"POST",headers:I,body:JSON.stringify(f)},t),S=await u.text(),v=P(S),l=Y(v,{}),h=l.resultCode,N=typeof h==="number"?h:typeof h==="string"?Number(h):NaN,g=typeof l.message==="string"&&l.message.length>0?l.message:"IWINV SMS history query failed";if(!u.ok||N!==0)return q(new W(Z.PROVIDER_ERROR,g,{providerId:t,originalCode:h??u.status}));let k=l.list,C=Array.isArray(k)?k:[];if(C.length===0)return se(null);let T=(()=>{return C.find((ee)=>{if(!D(ee))return!1;let F=ee.requestNo;return F!==void 0&&F!==null?String(F)===i:!1})??C[0]})();if(!D(T))return se(null);let j=typeof T.sendStatusCode==="string"?T.sendStatusCode:void 0,z=typeof T.sendStatusMsg==="string"?T.sendStatusMsg:typeof T.sendStatus==="string"?T.sendStatus:void 0,oe=te(T.sendDate),w=ze(j,z);return se({providerId:t,providerMessageId:i,status:w,statusCode:j,statusMessage:z,sentAt:oe,deliveredAt:w==="DELIVERED"?oe:void 0,failedAt:w==="FAILED"?oe:void 0,raw:T})}catch(u){return q(G(u,o?.signal,t))}}import{fail as R,KMsgError as x,KMsgErrorCode as K,ok as Ce}from"@k-msg/core";import{fail as Be,KMsgError as Qe,KMsgErrorCode as We,ok as Re}from"@k-msg/core";function je(e){let t=e.split(/[?#]/,1)[0]??e,n=t.lastIndexOf(".");if(n<=0||n===t.length-1)return"";return t.slice(n).toLowerCase()}function Ae(e){switch(je(e)){case".jpg":case".jpeg":return"image/jpeg";case".png":return"image/png";case".gif":return"image/gif";case".webp":return"image/webp";default:return}}function Ye(e,t){let n=e&&typeof e==="object"?e:{},o=(n.media&&typeof n.media==="object"?n.media:void 0)?.image;if(o&&typeof o==="object"){if(o.bytes instanceof Uint8Array)return Re({bytes:o.bytes,filename:typeof o.filename==="string"?o.filename:void 0,contentType:typeof o.contentType==="string"?o.contentType:void 0});if(o.blob instanceof Blob)return Re({blob:o.blob,filename:typeof o.filename==="string"?o.filename:void 0,contentType:typeof o.contentType==="string"?o.contentType:void 0});if(typeof o.ref==="string"&&o.ref.trim().length>0)return Be(new Qe(We.INVALID_REQUEST,"IWINV MMS caller must provide blob/bytes in options.media.image",{providerId:t,field:"media.image.ref"}))}let i=n.imageUrl;if(typeof i==="string"&&i.trim().length>0)return Be(new Qe(We.INVALID_REQUEST,"IWINV MMS caller must provide blob/bytes in options.media.image",{providerId:t,field:"imageUrl"}));return Re(void 0)}async function Je(e){if("blob"in e){let i=e.contentType||e.blob.type||"application/octet-stream",p=e.filename||"image",a=e.contentType&&e.contentType!==e.blob.type?new Blob([await e.blob.arrayBuffer()],{type:i}):e.blob;return{blob:a,filename:p,contentType:i,size:a.size}}let t=e.contentType||"application/octet-stream",n=new Uint8Array(e.bytes.byteLength);n.set(e.bytes);let r=new Blob([n],{type:t}),o=e.filename||"image";return{blob:r,filename:o,contentType:t,size:r.size}}function Ge(e){if(je(e.filename).length>0)return e.filename;let n=Ae(e.filename)==="image/png"?".png":Ae(e.filename)==="image/gif"?".gif":Ae(e.filename)==="image/webp"?".webp":e.contentType==="image/png"?".png":e.contentType==="image/gif"?".gif":e.contentType==="image/webp"?".webp":".jpg";return`${e.filename}${n}`}async function Xe(e){let{providerId:t,config:n,options:r,context:o}=e,i=r.templateId;if(!i||i.length===0)return R(new x(K.INVALID_REQUEST,"templateId is required for ALIMTALK",{providerId:t}));let p=r.options?.scheduledAt,a=p instanceof Date&&!Number.isNaN(p.getTime()),s=a?"Y":"N",c=a?pe(p):void 0,m=B(r.to);if(!m)return R(new x(K.INVALID_REQUEST,"to is required",{providerId:t}));let f=r.providerOptions?.templateParam,y=Array.isArray(f)?f.map((w)=>w===null||w===void 0?"":String(w)):Object.values(r.variables||{}).map((w)=>w===null||w===void 0?"":String(w)),d=r.failover,I=(typeof r.from==="string"&&r.from.length>0?r.from:n.senderNumber||n.smsSenderNumber)||"",b=I?B(I):"",u=typeof r.providerOptions?.reSend==="string"?r.providerOptions.reSend.trim().toUpperCase():"",S=u==="Y"||u==="N"?u:void 0,v=d?.enabled===!0?"Y":d?.enabled===!1?"N":void 0,l=S??v??(b?"Y":"N"),N=(typeof r.providerOptions?.resendCallback==="string"?B(r.providerOptions.resendCallback):"")||b;if(l==="Y"&&!N)return R(new x(K.INVALID_REQUEST,"resendCallback is required when reSend is 'Y' (options.from or providerOptions.resendCallback)",{providerId:t}));let g=typeof r.providerOptions?.resendType==="string"?r.providerOptions.resendType.trim().toUpperCase():"",k=g==="Y"||g==="N"?g:void 0;if(typeof r.providerOptions?.resendType==="string"&&r.providerOptions.resendType.length>0&&!k)return R(new x(K.INVALID_REQUEST,"resendType must be 'Y' or 'N'",{providerId:t}));let C=d?.fallbackChannel==="lms"?"Y":d?.fallbackChannel==="sms"?"N":void 0,T=typeof r.providerOptions?.resendTitle==="string"&&r.providerOptions.resendTitle.trim().length>0?r.providerOptions.resendTitle.trim():typeof d?.fallbackTitle==="string"&&d.fallbackTitle.trim().length>0?d.fallbackTitle.trim():void 0,j=typeof r.providerOptions?.resendContent==="string"&&r.providerOptions.resendContent.trim().length>0?r.providerOptions.resendContent.trim():typeof d?.fallbackContent==="string"&&d.fallbackContent.trim().length>0?d.fallbackContent.trim():void 0,z={templateCode:i,reserve:s,...c?{sendDate:c}:{},list:[{phone:m,templateParam:y.length>0?y:void 0}],reSend:l,...N?{resendCallback:N}:{},...k??C?{resendType:k??C}:{},...T?{resendTitle:T}:{},...j?{resendContent:j}:{}},oe=`${n.baseUrl}${xe(n)}`;try{let w=await ne(o,oe,{method:"POST",headers:M(n),body:JSON.stringify(z)},t),Ie=await w.text(),ee=P(Ie),F=D(ee)?ee:{code:L(ee)??w.status,message:Ie||String(ee||"")};if(!w.ok||F.code!==200)return R(new x(V(F.code),F.message||"IWINV send failed",{providerId:t,originalCode:F.code}));return Ce({messageId:r.messageId||crypto.randomUUID(),providerId:t,providerMessageId:typeof F.seqNo==="number"?String(F.seqNo):void 0,status:a?"PENDING":"SENT",type:r.type,to:r.to,raw:F})}catch(w){return R(G(w,o?.signal,t))}}async function it(e){let{providerId:t,config:n,options:r,to:o,from:i,text:p,scheduledAtValid:a,scheduledAt:s,context:c}=e;if(r.type!=="MMS")return R(new x(K.INVALID_REQUEST,"IWINVProvider: MMS handler called with non-MMS options",{providerId:t,type:r.type}));let m=Ee(p,r.subject),f=Ye(r,t);if(f.isFailure)return f;let y=f.value;if(!y)return R(new x(K.INVALID_REQUEST,"image is required for MMS; caller must provide options.media.image.blob or bytes",{providerId:t}));let d;try{d=await Je(y)}catch(l){return R(ye(l,t))}if(d.size>102400)return R(new x(K.INVALID_REQUEST,"MMS image must be <= 100KB",{providerId:t,bytes:d.size}));let I=new FormData;if(I.append("version","1.0"),I.append("from",i),I.append("to",o),I.append("title",m),I.append("text",p),a&&s)I.append("date",Te(s));I.append("image",d.blob,Ge(d));let u={secret:X(n)};if(typeof n.xForwardedFor==="string"&&n.xForwardedFor.length>0)u["X-Forwarded-For"]=n.xForwardedFor;let S={...u};if(n.extraHeaders&&typeof n.extraHeaders==="object")for(let[l,h]of Object.entries(n.extraHeaders)){if(l.toLowerCase()==="content-type")continue;S[l]=h}let v=`${Q()}/api/v2/send/`;try{let l=await ne(c,v,{method:"POST",headers:S,body:I},t),h=await l.text(),N=P(h),g=D(N)?N:{resultCode:N},k=g.resultCode??g.code,C=we(k),T=typeof g.message==="string"&&g.message.length>0?g.message:ve(C,"MMS send failed");if(!(l.ok&&C==="0"))return R(new x(he(C,l.ok),T,{providerId:t,originalCode:k}));let z=typeof g.requestNo==="string"&&g.requestNo.length>0?g.requestNo:typeof g.msgid==="string"&&g.msgid.length>0?g.msgid:void 0;return Ce({messageId:r.messageId||crypto.randomUUID(),providerId:t,providerMessageId:z,status:a?"PENDING":"SENT",type:r.type,to:r.to,raw:g})}catch(l){return R(G(l,c?.signal,t))}}async function Ze(e){let{providerId:t,config:n,options:r,context:o}=e;if(!re(n))return R(new x(K.INVALID_REQUEST,"SMS v2 configuration missing (smsApiKey/smsAuthKey)",{providerId:t}));let i=B(r.to);if(!i)return R(new x(K.INVALID_REQUEST,"to is required",{providerId:t}));let p=r.text;if(!p||p.trim().length===0)return R(new x(K.INVALID_REQUEST,"text is required for SMS/LMS/MMS",{providerId:t}));let a=(typeof r.from==="string"&&r.from.length>0?r.from:n.smsSenderNumber||n.senderNumber)||"",s=a?B(a):"";if(!s)return R(new x(K.INVALID_REQUEST,"from is required for SMS/LMS/MMS (options.from or config.smsSenderNumber)",{providerId:t}));let c=r.options?.scheduledAt,m=c instanceof Date&&!Number.isNaN(c.getTime());if(r.type==="MMS")return await it({providerId:t,config:n,options:r,to:i,from:s,text:p,scheduledAtValid:m,scheduledAt:m?c:void 0,context:o});let f={version:"1.0",from:s,to:[i],text:p};if(r.type==="LMS")f.title=Ee(p,r.subject);else{let u=typeof r.providerOptions?.msgType==="string"&&r.providerOptions.msgType.trim().length>0?r.providerOptions.msgType.trim():void 0;f.msgType=u||r.type}if(m)f.date=Te(c);let d={"Content-Type":"application/json;charset=UTF-8",secret:X(n)};if(typeof n.xForwardedFor==="string"&&n.xForwardedFor.length>0)d["X-Forwarded-For"]=n.xForwardedFor;let I=n.extraHeaders&&typeof n.extraHeaders==="object"?{...d,...n.extraHeaders}:d,b=`${Q()}/api/v2/send/`;try{let u=await ne(o,b,{method:"POST",headers:I,body:JSON.stringify(f)},t),S=await u.text(),v=P(S),l=D(v)?v:{resultCode:v},h=l.resultCode??l.code,N=we(h),g=typeof l.message==="string"&&l.message.length>0?l.message:ve(N,"SMS send failed");if(!(u.ok&&N==="0"))return R(new x(he(N,u.ok),g,{providerId:t,originalCode:h}));let C=typeof l.requestNo==="string"&&l.requestNo.length>0?l.requestNo:typeof l.msgid==="string"&&l.msgid.length>0?l.msgid:void 0;return Ce({messageId:r.messageId||crypto.randomUUID(),providerId:t,providerMessageId:C,status:m?"PENDING":"SENT",type:r.type,to:r.to,raw:l})}catch(u){return R(G(u,o?.signal,t))}}function at(e){return{...e,baseUrl:qe,sendEndpoint:e.sendEndpoint||"/api/v2/send/"}}function De(){return{apiKey:$("IWINV_API_KEY")||"",smsApiKey:$("IWINV_SMS_API_KEY"),smsAuthKey:$("IWINV_SMS_AUTH_KEY"),smsCompanyId:$("IWINV_SMS_COMPANY_ID"),senderNumber:$("IWINV_SENDER_NUMBER")||$("IWINV_SMS_SENDER_NUMBER"),smsSenderNumber:$("IWINV_SMS_SENDER_NUMBER"),sendEndpoint:$("IWINV_SEND_ENDPOINT")||"/api/v2/send/",xForwardedFor:$("IWINV_X_FORWARDED_FOR"),debug:$("NODE_ENV")==="development"}}class ie{id="iwinv";name="IWINV Messaging Provider";supportedTypes;transportCapabilities={abortSignal:"supported",injectableFetch:"supported"};config;getOnboardingSpec(){let e=Ue(this.id);if(!e)throw new O(_.INVALID_REQUEST,`Onboarding spec missing for provider: ${this.id}`,{providerId:this.id});return e}constructor(e){if(!e||typeof e!=="object")throw new O(_.INVALID_REQUEST,"IWINVProvider requires a config object",{providerId:this.id});if(!e.apiKey||e.apiKey.length===0)throw new O(_.INVALID_REQUEST,"IWINVProvider requires `apiKey` configuration",{providerId:this.id});this.config=at(e);let t=["ALIMTALK"];if(re(this.config))t.push("SMS","LMS","MMS");this.supportedTypes=t}async healthCheck(){let e=Date.now(),t=[];try{try{new URL(this.config.baseUrl)}catch{t.push("Invalid baseUrl")}if(re(this.config))try{new URL(Q())}catch{t.push("Invalid smsBaseUrl")}return{healthy:t.length===0,issues:t,latencyMs:Date.now()-e,data:{provider:this.id,baseUrl:this.config.baseUrl,smsBaseUrl:Q()}}}catch(n){return t.push(n instanceof Error?n.message:String(n)),{healthy:!1,issues:t,latencyMs:Date.now()-e}}}async send(e,t){let n=e.messageId||crypto.randomUUID(),r={...e,messageId:n};switch(r.type){case"ALIMTALK":return Xe({providerId:this.id,config:this.config,options:r,context:t});case"SMS":case"LMS":case"MMS":return Ze({providerId:this.id,config:this.config,options:r,context:t});default:return H(new O(_.INVALID_REQUEST,`IWINVProvider does not support type ${r.type}`,{providerId:this.id,type:r.type}))}}async getDeliveryStatus(e,t){switch(e.type){case"ALIMTALK":return He({providerId:this.id,config:this.config,query:e,context:t});case"SMS":case"LMS":case"MMS":return $e({providerId:this.id,config:this.config,query:e,context:t});default:return H(new O(_.INVALID_REQUEST,`IWINVProvider does not support type ${e.type}`,{providerId:this.id,type:e.type}))}}async getBalance(e){let t=e?.channel??"ALIMTALK";switch(t){case"ALIMTALK":return this.getAlimTalkBalance(t);case"SMS":case"LMS":case"MMS":return this.getSmsBalance(t);default:return H(new O(_.INVALID_REQUEST,`IWINVProvider does not support balance query for type ${t}`,{providerId:this.id,type:t}))}}async getAlimTalkBalance(e){let t=`${this.config.baseUrl}/api/charge/`;try{let n=await fetch(t,{method:"POST",headers:M(this.config),body:JSON.stringify({})}),r=await n.text(),o=P(r),i=Y(o,{}),p=i.code,a=typeof p==="string"?Number(p):void 0,s=typeof p==="number"?p:typeof a==="number"&&Number.isFinite(a)?a:void 0,c=typeof i.message==="string"&&i.message.length>0?i.message:"IWINV AlimTalk charge query failed";if(!n.ok||s!==200)return H(new O(V(s??n.status),c,{providerId:this.id,originalCode:p??n.status}));let m=i.charge,f=typeof m==="number"?m:typeof m==="string"?Number(m):NaN;if(!Number.isFinite(f))return H(new O(_.PROVIDER_ERROR,"Invalid charge value from IWINV AlimTalk charge API",{providerId:this.id,raw:i}));return et({providerId:this.id,channel:e,amount:f,currency:"KRW",raw:i})}catch(n){return H(new O(_.NETWORK_ERROR,n instanceof Error?n.message:String(n),{providerId:this.id}))}}async getSmsBalance(e){if(!this.config.smsApiKey||!this.config.smsAuthKey)return H(new O(_.INVALID_REQUEST,"smsApiKey and smsAuthKey are required for SMS/LMS/MMS balance query",{providerId:this.id}));let n={"Content-Type":"application/json;charset=UTF-8",secret:X(this.config)};if(typeof this.config.xForwardedFor==="string"&&this.config.xForwardedFor.length>0)n["X-Forwarded-For"]=this.config.xForwardedFor;let r=this.config.extraHeaders&&typeof this.config.extraHeaders==="object"?{...n,...this.config.extraHeaders}:n,o=`${Q()}/api/charge/`;try{let i=await fetch(o,{method:"POST",headers:r,body:JSON.stringify({version:"1.0"})}),p=await i.text(),a=P(p),s=Y(a,{}),c=s.code??s.resultCode,m=typeof c==="string"?Number(c):void 0,f=typeof c==="number"?c:typeof m==="number"&&Number.isFinite(m)?m:NaN,y=typeof s.message==="string"&&s.message.length>0?s.message:"IWINV SMS charge query failed";if(!i.ok||f!==0)return H(new O(_.PROVIDER_ERROR,y,{providerId:this.id,originalCode:c??i.status}));let d=s.charge,I=typeof d==="number"?d:typeof d==="string"?Number(d):NaN;if(!Number.isFinite(I))return H(new O(_.PROVIDER_ERROR,"Invalid charge value from IWINV SMS charge API",{providerId:this.id,raw:s}));return et({providerId:this.id,channel:e,amount:I,currency:"KRW",raw:s})}catch(i){return H(new O(_.NETWORK_ERROR,i instanceof Error?i.message:String(i),{providerId:this.id}))}}}var cn=(e)=>new ie(e),dt=()=>{let e=De();if(!e.apiKey)throw new O(_.INVALID_REQUEST,"IWINV_API_KEY environment variable is required",{providerId:"iwinv"});return new ie(e)};class pt{static create(e){return new ie(e)}static createDefault(){return dt()}}class ae extends ie{async createTemplate(e,t){return Pe({providerId:this.id,config:this.config,input:e})}async updateTemplate(e,t,n){return Me({providerId:this.id,config:this.config,code:e,patch:t,ctx:n})}async deleteTemplate(e,t){return Ve({providerId:this.id,config:this.config,code:e})}async getTemplate(e,t){return me({providerId:this.id,config:this.config,code:e,ctx:t})}async listTemplates(e,t){return Fe({providerId:this.id,config:this.config,query:e,ctx:t})}}var fn=(e)=>new ae(e),ct=()=>{let e=De();return new ae(e)};class ut{static create(e){return new ae(e)}static createDefault(){return ct()}}function gn(){}var In={SUCCESS:200,AUTH_FAILED:201,BAD_REQUEST:400,UNAUTHORIZED:401,FORBIDDEN:403,NOT_FOUND:404,TOO_MANY_REQUESTS:429,INTERNAL_SERVER_ERROR:500};export{ae as default,In as IWINV_STATUS_CODES,ae as IWINVProvider};
//# debugId=A0EE93934960CED564756E2164756E21
//# sourceMappingURL=index.mjs.map