@k-msg/provider 0.27.0 → 0.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aligo/aligo.helpers.d.ts +9 -24
- package/dist/aligo/aligo.shared.helpers.d.ts +22 -0
- package/dist/aligo/aligo.template.helpers.d.ts +2 -0
- package/dist/aligo/index.js +3 -3
- package/dist/aligo/index.mjs +3 -3
- package/dist/aligo/provider.d.ts +3 -28
- package/dist/aligo/provider.send.d.ts +38 -0
- package/dist/aligo/provider.template.d.ts +26 -0
- package/dist/aligo/send.d.ts +5 -0
- package/dist/aligo/send.js +5 -0
- package/dist/aligo/send.mjs +5 -0
- package/dist/aligo/template.d.ts +6 -0
- package/dist/aligo/template.js +5 -0
- package/dist/aligo/template.mjs +5 -0
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/dist/iwinv/index.js +2 -2
- package/dist/iwinv/index.mjs +2 -2
- package/dist/iwinv/provider.d.ts +3 -14
- package/dist/iwinv/provider.send.d.ts +24 -0
- package/dist/iwinv/send.d.ts +5 -0
- package/dist/iwinv/send.js +4 -0
- package/dist/iwinv/send.mjs +4 -0
- package/dist/iwinv/template.d.ts +24 -0
- package/dist/iwinv/template.js +4 -0
- package/dist/iwinv/template.mjs +4 -0
- package/package.json +28 -6
- package/dist/aligo/index.js.map +0 -18
- package/dist/aligo/index.mjs.map +0 -18
- package/dist/index.js.map +0 -32
- package/dist/index.mjs.map +0 -32
- package/dist/iwinv/index.js.map +0 -23
- package/dist/iwinv/index.mjs.map +0 -23
- package/dist/solapi/index.js.map +0 -16
- package/dist/solapi/index.mjs.map +0 -16
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{KMsgError as Ye,KMsgErrorCode as Je}from"@k-msg/core";var pe="https://alimtalk.bizservice.iwinv.kr",Ce="https://sms.bizservice.iwinv.kr";import{fail as h,KMsgError as A,KMsgErrorCode as U,ok as ie}from"@k-msg/core";import{validateTemplatePayload as ke}from"@k-msg/template/send";function x(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function M(e){if(!e)return{};try{return JSON.parse(e)}catch{return e}}function Y(e,t){return x(e)?e:t}import{KMsgErrorCode as J}from"@k-msg/core";function Ge(e){let t="",n=0;while(n<e.length){let r=e[n++]??0,s=e[n++]??0,a=e[n++]??0,p=r<<16|s<<8|a;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 re(e){return Ge(new TextEncoder().encode(e))}function Oe(e){let t=e.sendEndpoint||"/api/v2/send/";return t.startsWith("/")?t:`/${t}`}function P(e){let n={AUTH:re(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 xe(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 me(e){switch(typeof e==="string"?e.trim().toUpperCase():""){case"Y":return"APPROVED";case"I":return"INSPECTION";case"R":return"REJECTED";default:return"PENDING"}}function fe(e,t){return new Date(e.getTime()+t*24*60*60*1000)}function ge(e){let t=(n)=>n.toString().padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`}function Z(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]),s=Number(n[2]),a=Number(n[3]),p=Number(n[4]),o=Number(n[5]),i=Number(n[6]);if(!Number.isFinite(r)||!Number.isFinite(s)||!Number.isFinite(a)||!Number.isFinite(p)||!Number.isFinite(o)||!Number.isFinite(i))return;let c=new Date(r,s-1,a,p,o,i);if(Number.isNaN(c.getTime()))return;return c}function se(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 ye(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 ae(e){let t=await e.text(),n=M(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 Ie(e){let{providerId:t,config:n,input:r}=e;if(!r||typeof r!=="object")return h(new A(U.INVALID_REQUEST,"Template input is required",{providerId:t}));let s=ke(r,{requireName:!0,requireContent:!0});if(s.isFailure)return h(_e(s.error,t));let a=`${n.baseUrl}/api/template/add/`,p={templateName:s.value.name??r.name,templateContent:s.value.content??r.content,...s.value.buttons?{buttons:s.value.buttons}:{}};try{let o=await fetch(a,{method:"POST",headers:P(n),body:JSON.stringify(p)}),i=await ae(o),c=L(i.code)??o.status,f=typeof i.message==="string"&&i.message.length>0?i.message:"IWINV template create failed";if(!o.ok||c!==200)return h(new A(V(c),f,{providerId:t,originalCode:c}));let I=i.templateCode,d=typeof I==="string"&&I.trim().length>0?I.trim():"";if(!d)return h(new A(U.PROVIDER_ERROR,"IWINV template create did not return templateCode",{providerId:t,raw:i}));let m=new Date;return ie({id:d,code:d,name:s.value.name??r.name,content:s.value.content??r.content,category:r.category,status:"INSPECTION",buttons:s.value.buttons,variables:r.variables,createdAt:m,updatedAt:m})}catch(o){return h(new A(U.NETWORK_ERROR,o instanceof Error?o.message:String(o),{providerId:t}))}}async function be(e){let{providerId:t,config:n,code:r,patch:s,ctx:a}=e,p=typeof r==="string"?r.trim():"";if(!p)return h(new A(U.INVALID_REQUEST,"code is required",{providerId:t}));let o=await oe({providerId:t,config:n,code:p,ctx:a});if(o.isFailure)return o;let i=o.value,c=typeof s.name==="string"&&s.name.trim().length>0?s.name.trim():i.name,f=typeof s.content==="string"&&s.content.trim().length>0?s.content:i.content,I=s.buttons!==void 0?s.buttons:i.buttons,d=ke({name:c,content:f,buttons:I},{requireName:!0,requireContent:!0});if(d.isFailure)return h(_e(d.error,t));let m=`${n.baseUrl}/api/template/modify/`,w={templateCode:p,templateName:d.value.name??c,templateContent:d.value.content??f,...d.value.buttons?{buttons:d.value.buttons}:{}};try{let u=await fetch(m,{method:"POST",headers:P(n),body:JSON.stringify(w)}),g=await ae(u),S=L(g.code)??u.status,l=typeof g.message==="string"&&g.message.length>0?g.message:"IWINV template update failed";if(!u.ok||S!==200)return h(new A(V(S),l,{providerId:t,originalCode:S}));let b=await oe({providerId:t,config:n,code:p,ctx:a});if(b.isSuccess)return b;return ie({...i,name:d.value.name??c,content:d.value.content??f,...s.category!==void 0?{category:s.category}:{},...s.variables!==void 0?{variables:s.variables}:{},...s.buttons!==void 0?{buttons:d.value.buttons}:{},updatedAt:new Date})}catch(u){return h(new A(U.NETWORK_ERROR,u instanceof Error?u.message:String(u),{providerId:t}))}}async function Se(e){let{providerId:t,config:n,code:r}=e,s=typeof r==="string"?r.trim():"";if(!s)return h(new A(U.INVALID_REQUEST,"code is required",{providerId:t}));let a=`${n.baseUrl}/api/template/delete/`,p={templateCode:s};try{let o=await fetch(a,{method:"POST",headers:P(n),body:JSON.stringify(p)}),i=await ae(o),c=L(i.code)??o.status,f=typeof i.message==="string"&&i.message.length>0?i.message:typeof i.messgae==="string"&&i.messgae.length>0?i.messgae:"IWINV template delete failed";if(!o.ok||c!==200)return h(new A(V(c),f,{providerId:t,originalCode:c}));return ie(void 0)}catch(o){return h(new A(U.NETWORK_ERROR,o instanceof Error?o.message:String(o),{providerId:t}))}}async function oe(e){let{providerId:t,config:n,code:r}=e,s=typeof r==="string"?r.trim():"";if(!s)return h(new A(U.INVALID_REQUEST,"code is required",{providerId:t}));let a={pageNum:"1",pageSize:"15",templateCode:s},p=`${n.baseUrl}/api/template/`;try{let o=await fetch(p,{method:"POST",headers:P(n),body:JSON.stringify(a)}),i=await ae(o),c=L(i.code)??o.status,f=typeof i.message==="string"&&i.message.length>0?i.message:"IWINV template get failed";if(!o.ok||c!==200)return h(new A(V(c),f,{providerId:t,originalCode:c}));let I=i.list,m=(Array.isArray(I)?I:[]).find(x);if(!m)return h(new A(U.TEMPLATE_NOT_FOUND,"Template not found",{providerId:t,templateCode:s}));let w=m.templateCode,u=typeof w==="string"?w:String(w??""),g=typeof m.templateName==="string"?m.templateName:"",S=typeof m.templateContent==="string"?m.templateContent:"",l=me(m.status),b=Z(m.createDate)??new Date;return ie({id:u,code:u,name:g,content:S,status:l,buttons:Array.isArray(m.buttons)?m.buttons:void 0,createdAt:b,updatedAt:b})}catch(o){return h(new A(U.NETWORK_ERROR,o instanceof Error?o.message:String(o),{providerId:t}))}}async function Ne(e){let{providerId:t,config:n,query:r}=e,s=typeof r?.page==="number"&&r.page>0?Math.floor(r.page):1,a=typeof r?.limit==="number"&&r.limit>0?Math.floor(r.limit):15,p=xe(r?.status),o={pageNum:String(s),pageSize:String(a),...p?{templateStatus:p}:{}},i=`${n.baseUrl}/api/template/`;try{let c=await fetch(i,{method:"POST",headers:P(n),body:JSON.stringify(o)}),f=await ae(c),I=L(f.code)??c.status,d=typeof f.message==="string"&&f.message.length>0?f.message:"IWINV template list failed";if(!c.ok||I!==200)return h(new A(V(I),d,{providerId:t,originalCode:I}));let m=f.list,u=(Array.isArray(m)?m:[]).filter(x).map((g)=>{let S=g.templateCode,l=typeof S==="string"?S:String(S??""),b=typeof g.templateName==="string"?g.templateName:"",T=typeof g.templateContent==="string"?g.templateContent:"",y=me(g.status),D=Z(g.createDate)??new Date;return{id:l,code:l,name:b,content:T,status:y,buttons:Array.isArray(g.buttons)?g.buttons:void 0,createdAt:D,updatedAt:D}}).filter((g)=>g.code.length>0);return ie(u)}catch(c){return h(new A(U.NETWORK_ERROR,c instanceof Error?c.message:String(c),{providerId:t}))}}import{fail as $,KMsgError as k,KMsgErrorCode as _,ok as je,readRuntimeEnv as B}from"@k-msg/core";var Me={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 Pe(e){return Me[e]}function wt(){return Object.values(Me)}import{fail as K,KMsgError as q,KMsgErrorCode as H,ok as ne}from"@k-msg/core";import{KMsgErrorCode as de}from"@k-msg/core";function Q(e){return e.replace(/[^0-9]/g,"")}function W(){return Ce}function G(e){if(e.smsApiKey&&e.smsAuthKey)return re(`${e.smsApiKey}&${e.smsAuthKey}`);let t=e.smsAuthKey||e.smsApiKey;if(!t)return"";return re(`${e.apiKey}&${t}`)}function ee(e){return G(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 Te(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 Ee(e,t){if(e==="14"||e==="15"||e==="202"||e==="206")return de.AUTHENTICATION_FAILED;if(e==="50")return de.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 de.INVALID_REQUEST;if(!t)return de.NETWORK_ERROR;return de.PROVIDER_ERROR}function Re(e,t){if(t&&t.trim().length>0)return t.trim();return e.slice(0,20)}function Ve(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 Fe(e){let{providerId:t,config:n,query:r}=e,s=r.providerMessageId.trim();if(!s)return K(new q(H.INVALID_REQUEST,"providerMessageId is required",{providerId:t}));let a=Q(r.to);if(!a)return K(new q(H.INVALID_REQUEST,"to is required",{providerId:t}));let p=Number(s),o=Number.isFinite(p)?p:void 0,i=se(fe(r.requestedAt,-1)),c=se(new Date),f={pageNum:1,pageSize:15,phone:a,startDate:i,endDate:c,...o!==void 0?{seqNo:o}:{},...r.scheduledAt instanceof Date&&!Number.isNaN(r.scheduledAt.getTime())?{reserve:"Y"}:{}},I=`${n.baseUrl}/api/history/`;try{let d=await fetch(I,{method:"POST",headers:P(n),body:JSON.stringify(f)}),m=await d.text(),w=M(m),u=Y(w,{}),g=u.code,S=typeof g==="number"?g:void 0,l=typeof u.message==="string"&&u.message.length>0?u.message:"IWINV history query failed";if(!d.ok||S!==200)return K(new q(V(S??L(w)??d.status),l,{providerId:t,originalCode:g??d.status}));let b=u.list,T=Array.isArray(b)?b:[];if(T.length===0)return ne(null);let y=(()=>{if(o===void 0)return T[0];return T.find((N)=>x(N)&&N.seqNo===o)??T[0]})();if(!x(y))return ne(null);let D=typeof y.statusCode==="string"?y.statusCode:void 0,C=typeof y.statusCodeName==="string"?y.statusCodeName:void 0,E=Z(y.sendDate),j=Z(y.receiveDate),z=D==="OK"||typeof C==="string"&&C.includes("성공");return ne({providerId:t,providerMessageId:s,status:z?"DELIVERED":E?"FAILED":"PENDING",statusCode:D,statusMessage:C,sentAt:E,deliveredAt:z?j||E:void 0,failedAt:!z&&E?E:void 0,raw:y})}catch(d){return K(new q(H.NETWORK_ERROR,d instanceof Error?d.message:String(d),{providerId:t}))}}async function Le(e){let{providerId:t,config:n,query:r}=e;if(!ee(n))return K(new q(H.INVALID_REQUEST,"SMS v2 configuration missing (smsApiKey/smsAuthKey)",{providerId:t}));if(!n.smsCompanyId||n.smsCompanyId.length===0)return K(new q(H.INVALID_REQUEST,"smsCompanyId required for history (config.smsCompanyId)",{providerId:t}));let s=r.providerMessageId.trim();if(!s)return K(new q(H.INVALID_REQUEST,"providerMessageId is required",{providerId:t}));let a=Q(r.to);if(!a)return K(new q(H.INVALID_REQUEST,"to is required",{providerId:t}));let p=fe(r.requestedAt,-1),o=new Date;if(o.getTime()-p.getTime()>7776000000)return K(new q(H.INVALID_REQUEST,"SMS history date range must be within 90 days",{providerId:t}));let f={version:"1.0",companyid:n.smsCompanyId,startDate:ge(p),endDate:ge(o),requestNo:s,pageNum:1,pageSize:15,phone:a},d={"Content-Type":"application/json;charset=UTF-8",secret:G(n)};if(typeof n.xForwardedFor==="string"&&n.xForwardedFor.length>0)d["X-Forwarded-For"]=n.xForwardedFor;let m=n.extraHeaders&&typeof n.extraHeaders==="object"?{...d,...n.extraHeaders}:d,w=`${W()}/api/history/`;try{let u=await fetch(w,{method:"POST",headers:m,body:JSON.stringify(f)}),g=await u.text(),S=M(g),l=Y(S,{}),b=l.resultCode,T=typeof b==="number"?b:typeof b==="string"?Number(b):NaN,y=typeof l.message==="string"&&l.message.length>0?l.message:"IWINV SMS history query failed";if(!u.ok||T!==0)return K(new q(H.PROVIDER_ERROR,y,{providerId:t,originalCode:b??u.status}));let D=l.list,C=Array.isArray(D)?D:[];if(C.length===0)return ne(null);let E=(()=>{return C.find((X)=>{if(!x(X))return!1;let F=X.requestNo;return F!==void 0&&F!==null?String(F)===s:!1})??C[0]})();if(!x(E))return ne(null);let j=typeof E.sendStatusCode==="string"?E.sendStatusCode:void 0,z=typeof E.sendStatusMsg==="string"?E.sendStatusMsg:typeof E.sendStatus==="string"?E.sendStatus:void 0,te=Z(E.sendDate),N=Ve(j,z);return ne({providerId:t,providerMessageId:s,status:N,statusCode:j,statusMessage:z,sentAt:te,deliveredAt:N==="DELIVERED"?te:void 0,failedAt:N==="FAILED"?te:void 0,raw:E})}catch(u){return K(new q(H.NETWORK_ERROR,u instanceof Error?u.message:String(u),{providerId:t}))}}import{fail as v,KMsgError as R,KMsgErrorCode as O,ok as Ae}from"@k-msg/core";import{fail as Ue,KMsgError as Ke,KMsgErrorCode as qe,ok as he}from"@k-msg/core";function ze(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 ve(e){switch(ze(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 He(e,t){let n=e&&typeof e==="object"?e:{},s=(n.media&&typeof n.media==="object"?n.media:void 0)?.image;if(s&&typeof s==="object"){if(s.bytes instanceof Uint8Array)return he({bytes:s.bytes,filename:typeof s.filename==="string"?s.filename:void 0,contentType:typeof s.contentType==="string"?s.contentType:void 0});if(s.blob instanceof Blob)return he({blob:s.blob,filename:typeof s.filename==="string"?s.filename:void 0,contentType:typeof s.contentType==="string"?s.contentType:void 0});if(typeof s.ref==="string"&&s.ref.trim().length>0)return Ue(new Ke(qe.INVALID_REQUEST,"IWINV MMS caller must provide blob/bytes in options.media.image",{providerId:t,field:"media.image.ref"}))}let a=n.imageUrl;if(typeof a==="string"&&a.trim().length>0)return Ue(new Ke(qe.INVALID_REQUEST,"IWINV MMS caller must provide blob/bytes in options.media.image",{providerId:t,field:"imageUrl"}));return he(void 0)}async function $e(e){if("blob"in e){let a=e.contentType||e.blob.type||"application/octet-stream",p=e.filename||"image",o=e.contentType&&e.contentType!==e.blob.type?new Blob([await e.blob.arrayBuffer()],{type:a}):e.blob;return{blob:o,filename:p,contentType:a,size:o.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}),s=e.filename||"image";return{blob:r,filename:s,contentType:t,size:r.size}}function Be(e){if(ze(e.filename).length>0)return e.filename;let n=ve(e.filename)==="image/png"?".png":ve(e.filename)==="image/gif"?".gif":ve(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 Qe(e){let{providerId:t,config:n,options:r}=e,s=r.templateId;if(!s||s.length===0)return v(new R(O.INVALID_REQUEST,"templateId is required for ALIMTALK",{providerId:t}));let a=r.options?.scheduledAt,p=a instanceof Date&&!Number.isNaN(a.getTime()),o=p?"Y":"N",i=p?se(a):void 0,c=Q(r.to);if(!c)return v(new R(O.INVALID_REQUEST,"to is required",{providerId:t}));let f=r.providerOptions?.templateParam,I=Array.isArray(f)?f.map((N)=>N===null||N===void 0?"":String(N)):Object.values(r.variables||{}).map((N)=>N===null||N===void 0?"":String(N)),d=r.failover,m=(typeof r.from==="string"&&r.from.length>0?r.from:n.senderNumber||n.smsSenderNumber)||"",w=m?Q(m):"",u=typeof r.providerOptions?.reSend==="string"?r.providerOptions.reSend.trim().toUpperCase():"",g=u==="Y"||u==="N"?u:void 0,S=d?.enabled===!0?"Y":d?.enabled===!1?"N":void 0,l=g??S??(w?"Y":"N"),T=(typeof r.providerOptions?.resendCallback==="string"?Q(r.providerOptions.resendCallback):"")||w;if(l==="Y"&&!T)return v(new R(O.INVALID_REQUEST,"resendCallback is required when reSend is 'Y' (options.from or providerOptions.resendCallback)",{providerId:t}));let y=typeof r.providerOptions?.resendType==="string"?r.providerOptions.resendType.trim().toUpperCase():"",D=y==="Y"||y==="N"?y:void 0;if(typeof r.providerOptions?.resendType==="string"&&r.providerOptions.resendType.length>0&&!D)return v(new R(O.INVALID_REQUEST,"resendType must be 'Y' or 'N'",{providerId:t}));let C=d?.fallbackChannel==="lms"?"Y":d?.fallbackChannel==="sms"?"N":void 0,E=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:s,reserve:o,...i?{sendDate:i}:{},list:[{phone:c,templateParam:I.length>0?I:void 0}],reSend:l,...T?{resendCallback:T}:{},...D??C?{resendType:D??C}:{},...E?{resendTitle:E}:{},...j?{resendContent:j}:{}},te=`${n.baseUrl}${Oe(n)}`;try{let N=await fetch(te,{method:"POST",headers:P(n),body:JSON.stringify(z)}),ue=await N.text(),X=M(ue),F=x(X)?X:{code:L(X)??N.status,message:ue||String(X||"")};if(!N.ok||F.code!==200)return v(new R(V(F.code),F.message||"IWINV send failed",{providerId:t,originalCode:F.code}));return Ae({messageId:r.messageId||crypto.randomUUID(),providerId:t,providerMessageId:typeof F.seqNo==="number"?String(F.seqNo):void 0,status:p?"PENDING":"SENT",type:r.type,to:r.to,raw:F})}catch(N){return v(new R(O.NETWORK_ERROR,N instanceof Error?N.message:String(N),{providerId:t}))}}async function Xe(e){let{providerId:t,config:n,options:r,to:s,from:a,text:p,scheduledAtValid:o,scheduledAt:i}=e;if(r.type!=="MMS")return v(new R(O.INVALID_REQUEST,"IWINVProvider: MMS handler called with non-MMS options",{providerId:t,type:r.type}));let c=Re(p,r.subject),f=He(r,t);if(f.isFailure)return f;let I=f.value;if(!I)return v(new R(O.INVALID_REQUEST,"image is required for MMS; caller must provide options.media.image.blob or bytes",{providerId:t}));let d;try{d=await $e(I)}catch(l){return v(l instanceof R?l:new R(O.NETWORK_ERROR,l instanceof Error?l.message:String(l),{providerId:t}))}if(d.size>102400)return v(new R(O.INVALID_REQUEST,"MMS image must be <= 100KB",{providerId:t,bytes:d.size}));let m=new FormData;if(m.append("version","1.0"),m.append("from",a),m.append("to",s),m.append("title",c),m.append("text",p),o&&i)m.append("date",ye(i));m.append("image",d.blob,Be(d));let u={secret:G(n)};if(typeof n.xForwardedFor==="string"&&n.xForwardedFor.length>0)u["X-Forwarded-For"]=n.xForwardedFor;let g={...u};if(n.extraHeaders&&typeof n.extraHeaders==="object")for(let[l,b]of Object.entries(n.extraHeaders)){if(l.toLowerCase()==="content-type")continue;g[l]=b}let S=`${W()}/api/v2/send/`;try{let l=await fetch(S,{method:"POST",headers:g,body:m}),b=await l.text(),T=M(b),y=x(T)?T:{resultCode:T},D=y.resultCode??y.code,C=we(D),E=typeof y.message==="string"&&y.message.length>0?y.message:Te(C,"MMS send failed");if(!(l.ok&&C==="0"))return v(new R(Ee(C,l.ok),E,{providerId:t,originalCode:D}));let z=typeof y.requestNo==="string"&&y.requestNo.length>0?y.requestNo:typeof y.msgid==="string"&&y.msgid.length>0?y.msgid:void 0;return Ae({messageId:r.messageId||crypto.randomUUID(),providerId:t,providerMessageId:z,status:o?"PENDING":"SENT",type:r.type,to:r.to,raw:y})}catch(l){return v(new R(O.NETWORK_ERROR,l instanceof Error?l.message:String(l),{providerId:t}))}}async function We(e){let{providerId:t,config:n,options:r}=e;if(!ee(n))return v(new R(O.INVALID_REQUEST,"SMS v2 configuration missing (smsApiKey/smsAuthKey)",{providerId:t}));let s=Q(r.to);if(!s)return v(new R(O.INVALID_REQUEST,"to is required",{providerId:t}));let a=r.text;if(!a||a.trim().length===0)return v(new R(O.INVALID_REQUEST,"text is required for SMS/LMS/MMS",{providerId:t}));let p=(typeof r.from==="string"&&r.from.length>0?r.from:n.smsSenderNumber||n.senderNumber)||"",o=p?Q(p):"";if(!o)return v(new R(O.INVALID_REQUEST,"from is required for SMS/LMS/MMS (options.from or config.smsSenderNumber)",{providerId:t}));let i=r.options?.scheduledAt,c=i instanceof Date&&!Number.isNaN(i.getTime());if(r.type==="MMS")return await Xe({providerId:t,config:n,options:r,to:s,from:o,text:a,scheduledAtValid:c,scheduledAt:c?i:void 0});let f={version:"1.0",from:o,to:[s],text:a};if(r.type==="LMS")f.title=Re(a,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(c)f.date=ye(i);let d={"Content-Type":"application/json;charset=UTF-8",secret:G(n)};if(typeof n.xForwardedFor==="string"&&n.xForwardedFor.length>0)d["X-Forwarded-For"]=n.xForwardedFor;let m=n.extraHeaders&&typeof n.extraHeaders==="object"?{...d,...n.extraHeaders}:d,w=`${W()}/api/v2/send/`;try{let u=await fetch(w,{method:"POST",headers:m,body:JSON.stringify(f)}),g=await u.text(),S=M(g),l=x(S)?S:{resultCode:S},b=l.resultCode??l.code,T=we(b),y=typeof l.message==="string"&&l.message.length>0?l.message:Te(T,"SMS send failed");if(!(u.ok&&T==="0"))return v(new R(Ee(T,u.ok),y,{providerId:t,originalCode:b}));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 Ae({messageId:r.messageId||crypto.randomUUID(),providerId:t,providerMessageId:C,status:c?"PENDING":"SENT",type:r.type,to:r.to,raw:l})}catch(u){return v(new R(O.NETWORK_ERROR,u instanceof Error?u.message:String(u),{providerId:t}))}}function Ze(e){return{...e,baseUrl:pe,sendEndpoint:e.sendEndpoint||"/api/v2/send/"}}function De(){return{apiKey:B("IWINV_API_KEY")||"",smsApiKey:B("IWINV_SMS_API_KEY"),smsAuthKey:B("IWINV_SMS_AUTH_KEY"),smsCompanyId:B("IWINV_SMS_COMPANY_ID"),senderNumber:B("IWINV_SENDER_NUMBER")||B("IWINV_SMS_SENDER_NUMBER"),smsSenderNumber:B("IWINV_SMS_SENDER_NUMBER"),sendEndpoint:B("IWINV_SEND_ENDPOINT")||"/api/v2/send/",xForwardedFor:B("IWINV_X_FORWARDED_FOR"),debug:B("NODE_ENV")==="development"}}class ce{id="iwinv";name="IWINV Messaging Provider";supportedTypes;config;getOnboardingSpec(){let e=Pe(this.id);if(!e)throw new k(_.INVALID_REQUEST,`Onboarding spec missing for provider: ${this.id}`,{providerId:this.id});return e}constructor(e){if(!e||typeof e!=="object")throw new k(_.INVALID_REQUEST,"IWINVProvider requires a config object",{providerId:this.id});if(!e.apiKey||e.apiKey.length===0)throw new k(_.INVALID_REQUEST,"IWINVProvider requires `apiKey` configuration",{providerId:this.id});this.config=Ze(e);let t=["ALIMTALK"];if(ee(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(ee(this.config))try{new URL(W())}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:W()}}}catch(n){return t.push(n instanceof Error?n.message:String(n)),{healthy:!1,issues:t,latencyMs:Date.now()-e}}}async send(e){let t=e.messageId||crypto.randomUUID(),n={...e,messageId:t};switch(n.type){case"ALIMTALK":return Qe({providerId:this.id,config:this.config,options:n});case"SMS":case"LMS":case"MMS":return We({providerId:this.id,config:this.config,options:n});default:return $(new k(_.INVALID_REQUEST,`IWINVProvider does not support type ${n.type}`,{providerId:this.id,type:n.type}))}}async getDeliveryStatus(e){switch(e.type){case"ALIMTALK":return Fe({providerId:this.id,config:this.config,query:e});case"SMS":case"LMS":case"MMS":return Le({providerId:this.id,config:this.config,query:e});default:return $(new k(_.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 $(new k(_.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:P(this.config),body:JSON.stringify({})}),r=await n.text(),s=M(r),a=Y(s,{}),p=a.code,o=typeof p==="string"?Number(p):void 0,i=typeof p==="number"?p:typeof o==="number"&&Number.isFinite(o)?o:void 0,c=typeof a.message==="string"&&a.message.length>0?a.message:"IWINV AlimTalk charge query failed";if(!n.ok||i!==200)return $(new k(V(i??n.status),c,{providerId:this.id,originalCode:p??n.status}));let f=a.charge,I=typeof f==="number"?f:typeof f==="string"?Number(f):NaN;if(!Number.isFinite(I))return $(new k(_.PROVIDER_ERROR,"Invalid charge value from IWINV AlimTalk charge API",{providerId:this.id,raw:a}));return je({providerId:this.id,channel:e,amount:I,currency:"KRW",raw:a})}catch(n){return $(new k(_.NETWORK_ERROR,n instanceof Error?n.message:String(n),{providerId:this.id}))}}async getSmsBalance(e){if(!this.config.smsApiKey||!this.config.smsAuthKey)return $(new k(_.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:G(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,s=`${W()}/api/charge/`;try{let a=await fetch(s,{method:"POST",headers:r,body:JSON.stringify({version:"1.0"})}),p=await a.text(),o=M(p),i=Y(o,{}),c=i.code??i.resultCode,f=typeof c==="string"?Number(c):void 0,I=typeof c==="number"?c:typeof f==="number"&&Number.isFinite(f)?f:NaN,d=typeof i.message==="string"&&i.message.length>0?i.message:"IWINV SMS charge query failed";if(!a.ok||I!==0)return $(new k(_.PROVIDER_ERROR,d,{providerId:this.id,originalCode:c??a.status}));let m=i.charge,w=typeof m==="number"?m:typeof m==="string"?Number(m):NaN;if(!Number.isFinite(w))return $(new k(_.PROVIDER_ERROR,"Invalid charge value from IWINV SMS charge API",{providerId:this.id,raw:i}));return je({providerId:this.id,channel:e,amount:w,currency:"KRW",raw:i})}catch(a){return $(new k(_.NETWORK_ERROR,a instanceof Error?a.message:String(a),{providerId:this.id}))}}}var Xt=(e)=>new ce(e),et=()=>{let e=De();if(!e.apiKey)throw new k(_.INVALID_REQUEST,"IWINV_API_KEY environment variable is required",{providerId:"iwinv"});return new ce(e)};class tt{static create(e){return new ce(e)}static createDefault(){return et()}}function nt(e){return{...e,baseUrl:pe,sendEndpoint:e.sendEndpoint||"/api/v2/send/"}}class le{id="iwinv";config;constructor(e){if(!e||typeof e!=="object")throw new Ye(Je.INVALID_REQUEST,"IWINVTemplateProvider requires a config object",{providerId:this.id});if(!e.apiKey||e.apiKey.length===0)throw new Ye(Je.INVALID_REQUEST,"IWINVTemplateProvider requires `apiKey` configuration",{providerId:this.id});this.config=nt(e)}async createTemplate(e){return Ie({providerId:this.id,config:this.config,input:e})}async updateTemplate(e,t,n){return be({providerId:this.id,config:this.config,code:e,patch:t,ctx:n})}async deleteTemplate(e){return Se({providerId:this.id,config:this.config,code:e})}async getTemplate(e,t){return oe({providerId:this.id,config:this.config,code:e,ctx:t})}async listTemplates(e,t){return Ne({providerId:this.id,config:this.config,query:e,ctx:t})}}var sn=(e)=>new le(e),rt=()=>{let e=De();return new le(e)};class st{static create(e){return new le(e)}static createDefault(){return rt()}}export{be as updateTemplate,Ne as listTemplates,oe as getTemplate,Se as deleteTemplate,Ie as createTemplate,sn as createIWINVTemplateProvider,rt as createDefaultIWINVTemplateProvider,st as IWINVTemplateProviderFactory,le as IWINVTemplateProvider};
|
|
2
|
+
|
|
3
|
+
//# debugId=B5D54A4A417ABEDE64756E2164756E21
|
|
4
|
+
//# sourceMappingURL=template.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k-msg/provider",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.2",
|
|
4
4
|
"packageManager": "bun@1.3.8",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Complete provider system with adapters and implementations for K-Message platform",
|
|
@@ -19,11 +19,31 @@
|
|
|
19
19
|
"import": "./dist/aligo/index.mjs",
|
|
20
20
|
"require": "./dist/aligo/index.js"
|
|
21
21
|
},
|
|
22
|
+
"./aligo/send": {
|
|
23
|
+
"types": "./dist/aligo/send.d.ts",
|
|
24
|
+
"import": "./dist/aligo/send.mjs",
|
|
25
|
+
"require": "./dist/aligo/send.js"
|
|
26
|
+
},
|
|
27
|
+
"./aligo/template": {
|
|
28
|
+
"types": "./dist/aligo/template.d.ts",
|
|
29
|
+
"import": "./dist/aligo/template.mjs",
|
|
30
|
+
"require": "./dist/aligo/template.js"
|
|
31
|
+
},
|
|
22
32
|
"./iwinv": {
|
|
23
33
|
"types": "./dist/iwinv/index.d.ts",
|
|
24
34
|
"import": "./dist/iwinv/index.mjs",
|
|
25
35
|
"require": "./dist/iwinv/index.js"
|
|
26
36
|
},
|
|
37
|
+
"./iwinv/send": {
|
|
38
|
+
"types": "./dist/iwinv/send.d.ts",
|
|
39
|
+
"import": "./dist/iwinv/send.mjs",
|
|
40
|
+
"require": "./dist/iwinv/send.js"
|
|
41
|
+
},
|
|
42
|
+
"./iwinv/template": {
|
|
43
|
+
"types": "./dist/iwinv/template.d.ts",
|
|
44
|
+
"import": "./dist/iwinv/template.mjs",
|
|
45
|
+
"require": "./dist/iwinv/template.js"
|
|
46
|
+
},
|
|
27
47
|
"./solapi": {
|
|
28
48
|
"types": "./dist/solapi/index.d.ts",
|
|
29
49
|
"import": "./dist/solapi/index.mjs",
|
|
@@ -35,8 +55,8 @@
|
|
|
35
55
|
},
|
|
36
56
|
"scripts": {
|
|
37
57
|
"build": "bun run clean && bun run build:esm && bun run build:cjs && bun run build:types",
|
|
38
|
-
"build:esm": "bun build ./src/index.ts ./src/aligo/index.ts ./src/iwinv/index.ts ./src/solapi/index.ts --outdir ./dist --format esm --minify --sourcemap --entry-naming '[dir]/[name].mjs' --external 'bun:test' --external 'solapi' --external '@k-msg/*'",
|
|
39
|
-
"build:cjs": "bun build ./src/index.ts ./src/aligo/index.ts ./src/iwinv/index.ts ./src/solapi/index.ts --outdir ./dist --format cjs --minify --sourcemap --entry-naming '[dir]/[name].js' --external 'bun:test' --external 'solapi' --external '@k-msg/*'",
|
|
58
|
+
"build:esm": "bun build ./src/index.ts ./src/aligo/index.ts ./src/aligo/send.ts ./src/aligo/template.ts ./src/iwinv/index.ts ./src/iwinv/send.ts ./src/iwinv/template.ts ./src/solapi/index.ts --outdir ./dist --format esm --minify --sourcemap --entry-naming '[dir]/[name].mjs' --external 'bun:test' --external 'solapi' --external '@k-msg/*'",
|
|
59
|
+
"build:cjs": "bun build ./src/index.ts ./src/aligo/index.ts ./src/aligo/send.ts ./src/aligo/template.ts ./src/iwinv/index.ts ./src/iwinv/send.ts ./src/iwinv/template.ts ./src/solapi/index.ts --outdir ./dist --format cjs --minify --sourcemap --entry-naming '[dir]/[name].js' --external 'bun:test' --external 'solapi' --external '@k-msg/*'",
|
|
40
60
|
"build:types": "tsc",
|
|
41
61
|
"dev": "tsc --watch",
|
|
42
62
|
"test": "bun run test:unit",
|
|
@@ -51,8 +71,8 @@
|
|
|
51
71
|
"publish": "bun publish --access public"
|
|
52
72
|
},
|
|
53
73
|
"dependencies": {
|
|
54
|
-
"@k-msg/core": "0.27.
|
|
55
|
-
"@k-msg/template": "0.27.
|
|
74
|
+
"@k-msg/core": "0.27.2",
|
|
75
|
+
"@k-msg/template": "0.27.2"
|
|
56
76
|
},
|
|
57
77
|
"devDependencies": {
|
|
58
78
|
"@types/bun": "^1.3.9",
|
|
@@ -78,7 +98,9 @@
|
|
|
78
98
|
"adapter"
|
|
79
99
|
],
|
|
80
100
|
"files": [
|
|
81
|
-
"dist",
|
|
101
|
+
"dist/**/*.js",
|
|
102
|
+
"dist/**/*.mjs",
|
|
103
|
+
"dist/**/*.d.ts",
|
|
82
104
|
"README.md"
|
|
83
105
|
],
|
|
84
106
|
"repository": {
|
package/dist/aligo/index.js.map
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/aligo/provider.ts", "../src/onboarding/specs.ts", "../src/aligo/aligo.kakao.ts", "../src/shared/type-guards.ts", "../src/aligo/aligo.error.ts", "../src/aligo/aligo.helpers.ts", "../src/aligo/aligo.http.ts", "../src/aligo/aligo.send.ts", "../src/aligo/aligo.template.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import {\n type KakaoChannel,\n type KakaoChannelCategories,\n type KakaoChannelProvider,\n type KMsgError,\n type MessageType,\n type Provider,\n type ProviderHealthStatus,\n type Result,\n readRuntimeEnv,\n type SendOptions,\n type SendResult,\n type Template,\n type TemplateContext,\n type TemplateCreateInput,\n type TemplateInspectionProvider,\n type TemplateProvider,\n type TemplateUpdateInput,\n} from \"@k-msg/core\";\nimport { getProviderOnboardingSpec } from \"../onboarding/specs\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\nimport {\n addKakaoChannel,\n listKakaoChannelCategories,\n listKakaoChannels,\n requestKakaoChannelAuth,\n} from \"./aligo.kakao\";\nimport { sendWithAligo } from \"./aligo.send\";\nimport {\n createTemplate,\n deleteTemplate,\n getTemplate,\n listTemplates,\n requestTemplateInspection,\n updateTemplate,\n} from \"./aligo.template\";\nimport type { AligoConfig } from \"./types/aligo\";\n\nexport class AligoProvider\n implements\n Provider,\n TemplateProvider,\n TemplateInspectionProvider,\n KakaoChannelProvider\n{\n readonly id = \"aligo\";\n readonly name = \"Aligo Smart SMS\";\n readonly supportedTypes: readonly MessageType[] = [\n \"ALIMTALK\",\n \"FRIENDTALK\",\n \"SMS\",\n \"LMS\",\n \"MMS\",\n ];\n\n private readonly smsHost: string;\n private readonly alimtalkHost: string;\n\n getOnboardingSpec() {\n const spec = getProviderOnboardingSpec(this.id);\n if (!spec) {\n throw new Error(`Onboarding spec missing for provider: ${this.id}`);\n }\n return spec;\n }\n\n constructor(private readonly config: AligoConfig) {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"AligoProvider requires a config object\");\n }\n if (!config.apiKey || config.apiKey.length === 0) {\n throw new Error(\"AligoProvider requires `apiKey`\");\n }\n if (!config.userId || config.userId.length === 0) {\n throw new Error(\"AligoProvider requires `userId`\");\n }\n\n this.smsHost = config.smsBaseUrl || \"https://apis.aligo.in\";\n this.alimtalkHost = config.alimtalkBaseUrl || \"https://kakaoapi.aligo.in\";\n }\n\n private getRuntimeContext(): AligoRuntimeContext {\n return {\n providerId: this.id,\n config: this.config,\n smsHost: this.smsHost,\n alimtalkHost: this.alimtalkHost,\n };\n }\n\n async healthCheck(): Promise<ProviderHealthStatus> {\n const start = Date.now();\n const issues: string[] = [];\n\n try {\n if (!this.config.apiKey) issues.push(\"Missing apiKey\");\n if (!this.config.userId) issues.push(\"Missing userId\");\n if (!this.config.sender) {\n issues.push(\"Missing sender (default from)\");\n }\n\n try {\n new URL(this.smsHost);\n } catch {\n issues.push(\"Invalid smsBaseUrl\");\n }\n\n try {\n new URL(this.alimtalkHost);\n } catch {\n issues.push(\"Invalid alimtalkBaseUrl\");\n }\n\n return {\n healthy: issues.length === 0,\n issues,\n latencyMs: Date.now() - start,\n data: {\n provider: this.id,\n smsBaseUrl: this.smsHost,\n alimtalkBaseUrl: this.alimtalkHost,\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 return sendWithAligo(this.getRuntimeContext(), normalized);\n }\n\n async listKakaoChannels(params?: {\n plusId?: string;\n senderKey?: string;\n }): Promise<Result<KakaoChannel[], KMsgError>> {\n return listKakaoChannels(this.getRuntimeContext(), params);\n }\n\n async listKakaoChannelCategories(): Promise<\n Result<KakaoChannelCategories, KMsgError>\n > {\n return listKakaoChannelCategories(this.getRuntimeContext());\n }\n\n async requestKakaoChannelAuth(params: {\n plusId: string;\n phoneNumber: string;\n }): Promise<Result<void, KMsgError>> {\n return requestKakaoChannelAuth(this.getRuntimeContext(), params);\n }\n\n async addKakaoChannel(params: {\n plusId: string;\n authNum: string;\n phoneNumber: string;\n categoryCode: string;\n }): Promise<Result<KakaoChannel, KMsgError>> {\n return addKakaoChannel(this.getRuntimeContext(), params);\n }\n\n async createTemplate(\n input: TemplateCreateInput,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return createTemplate(this.getRuntimeContext(), input, ctx);\n }\n\n async updateTemplate(\n code: string,\n patch: TemplateUpdateInput,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return updateTemplate(this.getRuntimeContext(), code, patch, ctx);\n }\n\n async deleteTemplate(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n return deleteTemplate(this.getRuntimeContext(), code, ctx);\n }\n\n async getTemplate(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return getTemplate(this.getRuntimeContext(), code, ctx);\n }\n\n async listTemplates(\n params?: { status?: string; page?: number; limit?: number },\n ctx?: TemplateContext,\n ): Promise<Result<Template[], KMsgError>> {\n return listTemplates(this.getRuntimeContext(), params, ctx);\n }\n\n async requestTemplateInspection(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n return requestTemplateInspection(this.getRuntimeContext(), code, ctx);\n }\n}\n\nexport const createAligoProvider = (config: AligoConfig) =>\n new AligoProvider(config);\n\nexport const createDefaultAligoProvider = () => {\n const config: AligoConfig = {\n apiKey: readRuntimeEnv(\"ALIGO_API_KEY\") || \"\",\n userId: readRuntimeEnv(\"ALIGO_USER_ID\") || \"\",\n senderKey: readRuntimeEnv(\"ALIGO_SENDER_KEY\") || \"\",\n sender: readRuntimeEnv(\"ALIGO_SENDER\") || \"\",\n friendtalkEndpoint: readRuntimeEnv(\"ALIGO_FRIENDTALK_ENDPOINT\"),\n testMode: readRuntimeEnv(\"NODE_ENV\") !== \"production\",\n debug: readRuntimeEnv(\"NODE_ENV\") === \"development\",\n };\n\n if (!config.apiKey || !config.userId) {\n throw new Error(\"ALIGO_API_KEY and ALIGO_USER_ID are required\");\n }\n\n return new AligoProvider(config);\n};\n\n// biome-ignore lint/complexity/noStaticOnlyClass: kept as a factory for convenience\nexport class AligoProviderFactory {\n static create(config: AligoConfig): AligoProvider {\n return new AligoProvider(config);\n }\n\n static createDefault(): AligoProvider {\n return createDefaultAligoProvider();\n }\n}\n\nexport function initializeAligo(): void {}\n",
|
|
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 fail,\n type KakaoCategoryEntry,\n type KakaoChannel,\n type KakaoChannelCategories,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport { mapAligoKakaoError } from \"./aligo.error\";\nimport { parseAligoDateTime } from \"./aligo.helpers\";\nimport { ensureAligoKakaoOk, requestAligo } from \"./aligo.http\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\n\nexport async function listKakaoChannels(\n ctx: AligoRuntimeContext,\n params?: {\n plusId?: string;\n senderKey?: string;\n },\n): Promise<Result<KakaoChannel[], KMsgError>> {\n try {\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n ...(typeof params?.plusId === \"string\" && params.plusId.trim().length > 0\n ? { plusid: params.plusId.trim() }\n : {}),\n ...(typeof params?.senderKey === \"string\" &&\n params.senderKey.trim().length > 0\n ? { senderkey: params.senderKey.trim() }\n : {}),\n };\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/list/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const channels: KakaoChannel[] = list\n .filter(isObjectRecord)\n .map((item) => ({\n providerId: ctx.providerId,\n senderKey: String(item.senderKey ?? \"\"),\n plusId: typeof item.uuid === \"string\" ? item.uuid : undefined,\n name: typeof item.name === \"string\" ? item.name : undefined,\n status: typeof item.status === \"string\" ? item.status : undefined,\n createdAt: parseAligoDateTime(item.cdate),\n updatedAt: parseAligoDateTime(item.udate),\n raw: item,\n }))\n .filter((channel) => channel.senderKey.length > 0);\n\n return ok(channels);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function listKakaoChannelCategories(\n ctx: AligoRuntimeContext,\n): Promise<Result<KakaoChannelCategories, KMsgError>> {\n try {\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/category/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"category list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const data = isObjectRecord(response.data) ? response.data : {};\n\n const mapEntries = (raw: unknown): KakaoCategoryEntry[] => {\n const arr = Array.isArray(raw) ? raw : [];\n return arr\n .filter(isObjectRecord)\n .map((entry) => ({\n code: String(entry.code ?? \"\"),\n name: String(entry.name ?? \"\"),\n parentCode:\n typeof entry.parentCode === \"string\" && entry.parentCode.length > 0\n ? entry.parentCode\n : undefined,\n }))\n .filter((entry) => entry.code.length > 0);\n };\n\n return ok({\n first: mapEntries(data.firstBusinessType),\n second: mapEntries(data.secondBusinessType),\n third: mapEntries(data.thirdBusinessType),\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function requestKakaoChannelAuth(\n ctx: AligoRuntimeContext,\n params: {\n plusId: string;\n phoneNumber: string;\n },\n): Promise<Result<void, KMsgError>> {\n try {\n const plusId = params.plusId.trim();\n const phoneNumber = params.phoneNumber.trim();\n if (!plusId || !phoneNumber) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"plusId and phoneNumber are required\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/auth/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n plusid: plusId,\n phonenumber: phoneNumber,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel auth failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function addKakaoChannel(\n ctx: AligoRuntimeContext,\n params: {\n plusId: string;\n authNum: string;\n phoneNumber: string;\n categoryCode: string;\n },\n): Promise<Result<KakaoChannel, KMsgError>> {\n try {\n const plusId = params.plusId.trim();\n const authNum = params.authNum.trim();\n const phoneNumber = params.phoneNumber.trim();\n const categoryCode = params.categoryCode.trim();\n\n if (!plusId || !authNum || !phoneNumber || !categoryCode) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"plusId, authNum, phoneNumber, categoryCode are required\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/add/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n plusid: plusId,\n authnum: authNum,\n phonenumber: phoneNumber,\n categorycode: categoryCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel add failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const dataRaw = response.data;\n const data = Array.isArray(dataRaw)\n ? dataRaw.find(isObjectRecord)\n : isObjectRecord(dataRaw)\n ? dataRaw\n : undefined;\n\n if (!data) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"channel add returned empty data\",\n {\n providerId: ctx.providerId,\n raw: response,\n },\n ),\n );\n }\n\n const senderKey = String(data.senderKey ?? \"\");\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"channel add did not return senderKey\",\n { providerId: ctx.providerId, raw: data },\n ),\n );\n }\n\n return ok({\n providerId: ctx.providerId,\n senderKey,\n plusId: typeof data.uuid === \"string\" ? data.uuid : plusId,\n name: typeof data.name === \"string\" ? data.name : undefined,\n status: typeof data.status === \"string\" ? data.status : undefined,\n createdAt: parseAligoDateTime(data.cdate),\n updatedAt: parseAligoDateTime(data.udate),\n raw: data,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n",
|
|
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",
|
|
9
|
-
"import { KMsgError, KMsgErrorCode } from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\n\nexport function mapAligoKakaoError(\n error: unknown,\n providerId: string,\n): KMsgError {\n if (error instanceof KMsgError) return error;\n return new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n );\n}\n\nexport function mapAligoError(error: unknown, providerId: string): KMsgError {\n if (error instanceof KMsgError) return error;\n\n const record = isObjectRecord(error) ? error : {};\n const resultCodeRaw = record.result_code;\n const resultCode =\n resultCodeRaw !== undefined && resultCodeRaw !== null\n ? String(resultCodeRaw)\n : \"UNKNOWN\";\n\n const message =\n typeof record.message === \"string\" && record.message.length > 0\n ? record.message\n : typeof record.msg === \"string\" && record.msg.length > 0\n ? record.msg\n : error instanceof Error\n ? error.message\n : \"Unknown Aligo error\";\n\n let code: KMsgErrorCode = KMsgErrorCode.PROVIDER_ERROR;\n\n switch (resultCode) {\n case \"-100\":\n case \"-101\":\n code = KMsgErrorCode.AUTHENTICATION_FAILED;\n break;\n case \"-102\":\n case \"-201\":\n code = KMsgErrorCode.INSUFFICIENT_BALANCE;\n break;\n case \"-103\":\n case \"-105\":\n code = KMsgErrorCode.INVALID_REQUEST;\n break;\n case \"-501\":\n code = KMsgErrorCode.TEMPLATE_NOT_FOUND;\n break;\n default:\n code = KMsgErrorCode.PROVIDER_ERROR;\n }\n\n return new KMsgError(code, `${message} (code: ${resultCode})`, {\n providerId,\n resultCode,\n });\n}\n",
|
|
10
|
-
"import {\n KMsgError,\n KMsgErrorCode,\n type MessageBinaryInput,\n type Template,\n type TemplateContext,\n} from \"@k-msg/core\";\nimport {\n ButtonParser,\n interpolate,\n type TemplateButton,\n} from \"@k-msg/template\";\nimport type { AligoConfig } from \"./types/aligo\";\n\nexport function resolveImageRef(options: {\n imageUrl?: string;\n media?: { image?: MessageBinaryInput };\n providerId: string;\n}): string | undefined {\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 \"Aligo MMS/FriendTalk image requires `options.imageUrl` or `options.media.image.ref` (url/path).\",\n { providerId: options.providerId },\n );\n}\n\nexport function getAligoEndpoint(\n operation: \"sendSMS\" | \"sendAlimTalk\" | \"sendFriendTalk\",\n config: AligoConfig,\n): string {\n switch (operation) {\n case \"sendSMS\":\n return \"/send/\";\n case \"sendAlimTalk\":\n return \"/akv10/alimtalk/send/\";\n case \"sendFriendTalk\":\n return config.friendtalkEndpoint || \"/akv10/friendtalk/send/\";\n default:\n return \"/\";\n }\n}\n\nexport function formatAligoDate(date: Date): { date: string; time: string } {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n\n return {\n date: `${year}${month}${day}`,\n time: `${hours}${minutes}`,\n };\n}\n\nexport function normalizeAligoKakaoCode(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n const num = Number(trimmed);\n if (Number.isFinite(num)) return num;\n }\n return undefined;\n}\n\nexport function resolveKakaoSenderKey(\n params: {\n providerId: string;\n config: AligoConfig;\n },\n ctx?: TemplateContext,\n): string {\n const senderKey =\n (typeof ctx?.kakaoChannelSenderKey === \"string\" &&\n ctx.kakaoChannelSenderKey.trim().length > 0\n ? ctx.kakaoChannelSenderKey.trim()\n : params.config.senderKey) || \"\";\n if (!senderKey) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao channel senderKey is required (ctx.kakaoChannelSenderKey or config.senderKey)\",\n { providerId: params.providerId },\n );\n }\n return senderKey;\n}\n\nexport function toAligoTplButton(\n buttons: TemplateButton[] | undefined,\n): string | undefined {\n if (!Array.isArray(buttons) || buttons.length === 0) return undefined;\n\n const serializedButtons = JSON.parse(\n ButtonParser.serializeButtons(buttons),\n ) as unknown[];\n return JSON.stringify({ button: serializedButtons });\n}\n\nexport function mapAligoTemplateStatus(\n item: Record<string, unknown>,\n): Template[\"status\"] {\n const insp =\n typeof item.inspStatus === \"string\"\n ? item.inspStatus.trim().toUpperCase()\n : \"\";\n switch (insp) {\n case \"APR\":\n return \"APPROVED\";\n case \"REJ\":\n return \"REJECTED\";\n case \"REQ\":\n case \"REG\":\n return \"INSPECTION\";\n default:\n return \"PENDING\";\n }\n}\n\nexport function parseAligoDateTime(value: unknown): Date | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})\\s+(\\d{2}):(\\d{2}):(\\d{2})$/.exec(\n trimmed,\n );\n if (!match) return undefined;\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const hour = Number(match[4]);\n const minute = Number(match[5]);\n const second = Number(match[6]);\n\n const date = new Date(year, month - 1, day, hour, minute, second);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\nexport function resolveAligoTemplateMessage(\n variables: Record<string, unknown> | undefined,\n templateContent?: string,\n): string {\n if (!variables) return \"\";\n const fullText = variables._full_text;\n if (fullText !== undefined && fullText !== null) return String(fullText);\n if (!templateContent) return Object.values(variables).map(String).join(\"\\n\");\n\n return interpolate(templateContent, variables);\n}\n",
|
|
11
|
-
"import { fail, KMsgError, KMsgErrorCode, ok, type Result } from \"@k-msg/core\";\nimport { normalizeAligoKakaoCode } from \"./aligo.helpers\";\n\nexport async function requestAligo(params: {\n host: string;\n endpoint: string;\n data: Record<string, unknown>;\n providerId: string;\n}): Promise<Record<string, unknown>> {\n const formData = new FormData();\n for (const [key, value] of Object.entries(params.data)) {\n if (value !== undefined && value !== null) {\n formData.append(key, String(value));\n }\n }\n\n const response = await fetch(`${params.host}${params.endpoint}`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n throw new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n `HTTP error! status: ${response.status}`,\n { providerId: params.providerId },\n );\n }\n\n return (await response.json()) as Record<string, unknown>;\n}\n\nexport function ensureAligoKakaoOk(params: {\n providerId: string;\n response: Record<string, unknown>;\n fallbackMessage: string;\n}): Result<void, KMsgError> {\n const { providerId, response, fallbackMessage } = params;\n const rawCode = response.code;\n const code = normalizeAligoKakaoCode(rawCode);\n if (code === 0) return ok(undefined);\n\n const message =\n typeof response.message === \"string\" && response.message.length > 0\n ? response.message\n : fallbackMessage;\n const mapped =\n code === 509 || code === -99\n ? KMsgErrorCode.INVALID_REQUEST\n : KMsgErrorCode.PROVIDER_ERROR;\n return fail(\n new KMsgError(mapped, message, {\n providerId,\n originalCode: rawCode,\n raw: response,\n }),\n );\n}\n",
|
|
12
|
-
"import {\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n type SendOptions,\n type SendResult,\n} from \"@k-msg/core\";\nimport { mapAligoError } from \"./aligo.error\";\nimport {\n formatAligoDate,\n getAligoEndpoint,\n resolveAligoTemplateMessage,\n resolveImageRef,\n} from \"./aligo.helpers\";\nimport { requestAligo } from \"./aligo.http\";\nimport type {\n AligoMessageType,\n AligoRuntimeContext,\n} from \"./aligo.internal.types\";\nimport type { AligoResponse, AligoSMSRequest } from \"./types/aligo\";\n\nexport function collectSendWarnings(\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 \"Aligo failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.\",\n details: {\n providerId,\n mappedFields: [\"failover\", \"fmessage_1\", \"fsubject_1\"],\n unsupportedFields: [\"fallbackChannel\"],\n },\n },\n ];\n}\n\nasync function sendSMS(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"SMS\" | \"LMS\" | \"MMS\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for SMS/LMS/MMS (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const body: AligoSMSRequest = {\n key: ctx.config.apiKey,\n user_id: ctx.config.userId,\n sender,\n receiver: options.to,\n msg: options.text,\n msg_type: options.type,\n title: options.subject,\n testmode_yn: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.rdate = date;\n body.rtime = time;\n }\n\n if (options.type === \"MMS\") {\n const imageRef = resolveImageRef({\n imageUrl: options.imageUrl,\n media: options.media,\n providerId: ctx.providerId,\n });\n if (!imageRef) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"image is required for MMS (options.imageUrl or options.media.image.ref)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n body.image = imageRef;\n }\n\n const response = (await requestAligo({\n host: ctx.smsHost,\n endpoint: getAligoEndpoint(\"sendSMS\", ctx.config),\n data: body as unknown as Record<string, unknown>,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"1\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n raw: response,\n });\n}\n\nasync function sendAlimTalk(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"ALIMTALK\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const warnings = collectSendWarnings(options, ctx.providerId);\n const senderKey =\n (typeof options.kakao?.profileId === \"string\"\n ? options.kakao.profileId\n : ctx.config.senderKey) || \"\";\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.senderKey)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for ALIMTALK (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const variables = options.variables as Record<string, unknown>;\n const templateId = options.templateId;\n if (!templateId || templateId.length === 0) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"templateId is required for ALIMTALK\",\n { providerId: ctx.providerId },\n ),\n );\n }\n const templateContent =\n typeof options.providerOptions?.templateContent === \"string\"\n ? options.providerOptions.templateContent\n : undefined;\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateId,\n sender,\n receiver_1: options.to,\n subject_1: \"알림톡\",\n message_1: resolveAligoTemplateMessage(variables, templateContent),\n testMode: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const failoverOverrideRaw =\n typeof options.providerOptions?.failover === \"string\"\n ? options.providerOptions.failover.trim().toUpperCase()\n : \"\";\n const failoverOverride =\n failoverOverrideRaw === \"Y\" || failoverOverrideRaw === \"N\"\n ? failoverOverrideRaw\n : undefined;\n const failoverFromOptions =\n options.failover?.enabled === true\n ? \"Y\"\n : options.failover?.enabled === false\n ? \"N\"\n : undefined;\n const failover = failoverOverride ?? failoverFromOptions;\n\n const fallbackTitle =\n typeof options.providerOptions?.fsubject_1 === \"string\" &&\n options.providerOptions.fsubject_1.trim().length > 0\n ? options.providerOptions.fsubject_1.trim()\n : typeof options.failover?.fallbackTitle === \"string\" &&\n options.failover.fallbackTitle.trim().length > 0\n ? options.failover.fallbackTitle.trim()\n : undefined;\n const fallbackContent =\n typeof options.providerOptions?.fmessage_1 === \"string\" &&\n options.providerOptions.fmessage_1.trim().length > 0\n ? options.providerOptions.fmessage_1.trim()\n : typeof options.failover?.fallbackContent === \"string\" &&\n options.failover.fallbackContent.trim().length > 0\n ? options.failover.fallbackContent.trim()\n : undefined;\n\n if (failover) {\n body.failover = failover;\n }\n if (fallbackTitle) {\n body.fsubject_1 = fallbackTitle;\n }\n if (fallbackContent) {\n body.fmessage_1 = fallbackContent;\n }\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.reserve = \"Y\";\n body.reserve_date = date;\n body.reserve_time = time;\n }\n\n const response = (await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: getAligoEndpoint(\"sendAlimTalk\", ctx.config),\n data: body,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"0\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n ...(Array.isArray(warnings) && warnings.length > 0 ? { warnings } : {}),\n raw: response,\n });\n}\n\nasync function sendFriendTalk(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"FRIENDTALK\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const senderKey =\n (typeof options.kakao?.profileId === \"string\"\n ? options.kakao.profileId\n : ctx.config.senderKey) || \"\";\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.senderKey)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for FRIENDTALK (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n sender,\n receiver_1: options.to,\n subject_1: \"친구톡\",\n message_1: options.text,\n testMode: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const imageRef = resolveImageRef({\n imageUrl: options.imageUrl,\n media: options.media,\n providerId: ctx.providerId,\n });\n if (imageRef) {\n body.image_1 = imageRef;\n }\n\n const buttons = Array.isArray(options.kakao?.buttons)\n ? options.kakao.buttons\n : options.buttons;\n if (buttons) {\n body.button_1 = JSON.stringify(buttons);\n }\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.reserve = \"Y\";\n body.reserve_date = date;\n body.reserve_time = time;\n }\n\n const response = (await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: getAligoEndpoint(\"sendFriendTalk\", ctx.config),\n data: body,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"0\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n raw: response,\n });\n}\n\nexport async function sendWithAligo(\n ctx: AligoRuntimeContext,\n options: SendOptions,\n): Promise<Result<SendResult, KMsgError>> {\n try {\n switch (options.type as AligoMessageType) {\n case \"ALIMTALK\":\n return await sendAlimTalk(\n ctx,\n options as Extract<SendOptions, { type: \"ALIMTALK\" }>,\n );\n case \"FRIENDTALK\":\n return await sendFriendTalk(\n ctx,\n options as Extract<SendOptions, { type: \"FRIENDTALK\" }>,\n );\n case \"SMS\":\n case \"LMS\":\n case \"MMS\":\n return await sendSMS(\n ctx,\n options as Extract<SendOptions, { type: \"SMS\" | \"LMS\" | \"MMS\" }>,\n );\n default:\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `AligoProvider does not support type ${options.type}`,\n { providerId: ctx.providerId, type: options.type },\n ),\n );\n }\n } catch (error) {\n return fail(mapAligoError(error, ctx.providerId));\n }\n}\n",
|
|
13
|
-
"import {\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n type Template,\n type TemplateContext,\n type TemplateCreateInput,\n type TemplateUpdateInput,\n} from \"@k-msg/core\";\nimport { validateTemplatePayload } from \"@k-msg/template\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport { mapAligoKakaoError } from \"./aligo.error\";\nimport {\n mapAligoTemplateStatus,\n parseAligoDateTime,\n resolveKakaoSenderKey,\n toAligoTplButton,\n} from \"./aligo.helpers\";\nimport { ensureAligoKakaoOk, requestAligo } from \"./aligo.http\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\n\nfunction withProviderContext(error: KMsgError, providerId: string): KMsgError {\n return new KMsgError(error.code, error.message, {\n providerId,\n ...(error.details ?? {}),\n });\n}\n\nexport async function createTemplate(\n ctx: AligoRuntimeContext,\n input: TemplateCreateInput,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const payloadValidation = validateTemplatePayload(input, {\n requireName: true,\n requireContent: true,\n });\n if (payloadValidation.isFailure) {\n return fail(withProviderContext(payloadValidation.error, ctx.providerId));\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_name: payloadValidation.value.name ?? input.name,\n tpl_content: payloadValidation.value.content ?? input.content,\n };\n\n const tplButton = toAligoTplButton(payloadValidation.value.buttons);\n if (tplButton) body.tpl_button = tplButton;\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/add/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template create failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const data = isObjectRecord(response.data) ? response.data : {};\n const code = String(data.templtCode ?? \"\");\n if (!code) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"template create did not return templtCode\",\n { providerId: ctx.providerId, raw: response },\n ),\n );\n }\n\n const createdAt = parseAligoDateTime(data.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(data.udate) ??\n parseAligoDateTime(data.cdate) ??\n createdAt;\n\n return ok({\n id: code,\n code,\n name: String(\n data.templtName ?? payloadValidation.value.name ?? input.name,\n ),\n content: String(\n data.templtContent ?? payloadValidation.value.content ?? input.content,\n ),\n category: input.category,\n status: mapAligoTemplateStatus(data),\n buttons: Array.isArray(data.buttons)\n ? data.buttons\n : payloadValidation.value.buttons,\n variables: input.variables,\n createdAt,\n updatedAt,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function getTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/list/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template get failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const first = list.find(isObjectRecord);\n if (!first) {\n return fail(\n new KMsgError(KMsgErrorCode.TEMPLATE_NOT_FOUND, \"Template not found\", {\n providerId: ctx.providerId,\n templateCode,\n }),\n );\n }\n\n const tplCode = String(first.templtCode ?? templateCode);\n const createdAt = parseAligoDateTime(first.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(first.udate) ??\n parseAligoDateTime(first.cdate) ??\n createdAt;\n\n return ok({\n id: tplCode,\n code: tplCode,\n name: String(first.templtName ?? \"\"),\n content: String(first.templtContent ?? \"\"),\n status: mapAligoTemplateStatus(first),\n buttons: Array.isArray(first.buttons) ? first.buttons : undefined,\n createdAt,\n updatedAt,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function updateTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n patch: TemplateUpdateInput,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const existingResult = await getTemplate(ctx, templateCode, {\n kakaoChannelSenderKey: senderKey,\n });\n if (existingResult.isFailure) return existingResult;\n const existing = existingResult.value;\n\n const nextName =\n typeof patch.name === \"string\" && patch.name.trim().length > 0\n ? patch.name.trim()\n : existing.name;\n const nextContent =\n typeof patch.content === \"string\" && patch.content.trim().length > 0\n ? patch.content\n : existing.content;\n const payloadValidation = validateTemplatePayload(\n {\n name: nextName,\n content: nextContent,\n buttons: patch.buttons !== undefined ? patch.buttons : existing.buttons,\n },\n {\n requireName: true,\n requireContent: true,\n },\n );\n if (payloadValidation.isFailure) {\n return fail(withProviderContext(payloadValidation.error, ctx.providerId));\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n tpl_name: payloadValidation.value.name ?? nextName,\n tpl_content: payloadValidation.value.content ?? nextContent,\n };\n\n const tplButton = toAligoTplButton(payloadValidation.value.buttons);\n if (tplButton) body.tpl_button = tplButton;\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/modify/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template update failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const refreshed = await getTemplate(ctx, templateCode, {\n kakaoChannelSenderKey: senderKey,\n });\n if (refreshed.isSuccess) return refreshed;\n\n return ok({\n ...existing,\n name: payloadValidation.value.name ?? nextName,\n content: payloadValidation.value.content ?? nextContent,\n ...(patch.category !== undefined ? { category: patch.category } : {}),\n ...(patch.variables !== undefined ? { variables: patch.variables } : {}),\n ...(patch.buttons !== undefined\n ? { buttons: payloadValidation.value.buttons }\n : {}),\n updatedAt: new Date(),\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function deleteTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<void, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/del/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template delete failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function listTemplates(\n ctx: AligoRuntimeContext,\n params?: { status?: string; page?: number; limit?: number },\n templateCtx?: TemplateContext,\n): Promise<Result<Template[], KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/list/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const templates = list\n .filter(isObjectRecord)\n .map((item) => {\n const tplCode = String(item.templtCode ?? \"\");\n const createdAt = parseAligoDateTime(item.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(item.udate) ??\n parseAligoDateTime(item.cdate) ??\n createdAt;\n\n return {\n id: tplCode,\n code: tplCode,\n name: String(item.templtName ?? \"\"),\n content: String(item.templtContent ?? \"\"),\n status: mapAligoTemplateStatus(item),\n buttons: Array.isArray(item.buttons) ? item.buttons : undefined,\n createdAt,\n updatedAt,\n } satisfies Template;\n })\n .filter((template) => template.code.length > 0);\n\n if (params?.status) {\n const status = params.status.trim().toUpperCase();\n return ok(templates.filter((template) => template.status === status));\n }\n\n return ok(templates);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function requestTemplateInspection(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<void, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/request/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template inspection request failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n"
|
|
14
|
-
],
|
|
15
|
-
"mappings": "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",
|
|
16
|
-
"debugId": "C790C7C50E6B04EA64756E2164756E21",
|
|
17
|
-
"names": []
|
|
18
|
-
}
|
package/dist/aligo/index.mjs.map
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/aligo/provider.ts", "../src/onboarding/specs.ts", "../src/aligo/aligo.kakao.ts", "../src/shared/type-guards.ts", "../src/aligo/aligo.error.ts", "../src/aligo/aligo.helpers.ts", "../src/aligo/aligo.http.ts", "../src/aligo/aligo.send.ts", "../src/aligo/aligo.template.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import {\n type KakaoChannel,\n type KakaoChannelCategories,\n type KakaoChannelProvider,\n type KMsgError,\n type MessageType,\n type Provider,\n type ProviderHealthStatus,\n type Result,\n readRuntimeEnv,\n type SendOptions,\n type SendResult,\n type Template,\n type TemplateContext,\n type TemplateCreateInput,\n type TemplateInspectionProvider,\n type TemplateProvider,\n type TemplateUpdateInput,\n} from \"@k-msg/core\";\nimport { getProviderOnboardingSpec } from \"../onboarding/specs\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\nimport {\n addKakaoChannel,\n listKakaoChannelCategories,\n listKakaoChannels,\n requestKakaoChannelAuth,\n} from \"./aligo.kakao\";\nimport { sendWithAligo } from \"./aligo.send\";\nimport {\n createTemplate,\n deleteTemplate,\n getTemplate,\n listTemplates,\n requestTemplateInspection,\n updateTemplate,\n} from \"./aligo.template\";\nimport type { AligoConfig } from \"./types/aligo\";\n\nexport class AligoProvider\n implements\n Provider,\n TemplateProvider,\n TemplateInspectionProvider,\n KakaoChannelProvider\n{\n readonly id = \"aligo\";\n readonly name = \"Aligo Smart SMS\";\n readonly supportedTypes: readonly MessageType[] = [\n \"ALIMTALK\",\n \"FRIENDTALK\",\n \"SMS\",\n \"LMS\",\n \"MMS\",\n ];\n\n private readonly smsHost: string;\n private readonly alimtalkHost: string;\n\n getOnboardingSpec() {\n const spec = getProviderOnboardingSpec(this.id);\n if (!spec) {\n throw new Error(`Onboarding spec missing for provider: ${this.id}`);\n }\n return spec;\n }\n\n constructor(private readonly config: AligoConfig) {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"AligoProvider requires a config object\");\n }\n if (!config.apiKey || config.apiKey.length === 0) {\n throw new Error(\"AligoProvider requires `apiKey`\");\n }\n if (!config.userId || config.userId.length === 0) {\n throw new Error(\"AligoProvider requires `userId`\");\n }\n\n this.smsHost = config.smsBaseUrl || \"https://apis.aligo.in\";\n this.alimtalkHost = config.alimtalkBaseUrl || \"https://kakaoapi.aligo.in\";\n }\n\n private getRuntimeContext(): AligoRuntimeContext {\n return {\n providerId: this.id,\n config: this.config,\n smsHost: this.smsHost,\n alimtalkHost: this.alimtalkHost,\n };\n }\n\n async healthCheck(): Promise<ProviderHealthStatus> {\n const start = Date.now();\n const issues: string[] = [];\n\n try {\n if (!this.config.apiKey) issues.push(\"Missing apiKey\");\n if (!this.config.userId) issues.push(\"Missing userId\");\n if (!this.config.sender) {\n issues.push(\"Missing sender (default from)\");\n }\n\n try {\n new URL(this.smsHost);\n } catch {\n issues.push(\"Invalid smsBaseUrl\");\n }\n\n try {\n new URL(this.alimtalkHost);\n } catch {\n issues.push(\"Invalid alimtalkBaseUrl\");\n }\n\n return {\n healthy: issues.length === 0,\n issues,\n latencyMs: Date.now() - start,\n data: {\n provider: this.id,\n smsBaseUrl: this.smsHost,\n alimtalkBaseUrl: this.alimtalkHost,\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 return sendWithAligo(this.getRuntimeContext(), normalized);\n }\n\n async listKakaoChannels(params?: {\n plusId?: string;\n senderKey?: string;\n }): Promise<Result<KakaoChannel[], KMsgError>> {\n return listKakaoChannels(this.getRuntimeContext(), params);\n }\n\n async listKakaoChannelCategories(): Promise<\n Result<KakaoChannelCategories, KMsgError>\n > {\n return listKakaoChannelCategories(this.getRuntimeContext());\n }\n\n async requestKakaoChannelAuth(params: {\n plusId: string;\n phoneNumber: string;\n }): Promise<Result<void, KMsgError>> {\n return requestKakaoChannelAuth(this.getRuntimeContext(), params);\n }\n\n async addKakaoChannel(params: {\n plusId: string;\n authNum: string;\n phoneNumber: string;\n categoryCode: string;\n }): Promise<Result<KakaoChannel, KMsgError>> {\n return addKakaoChannel(this.getRuntimeContext(), params);\n }\n\n async createTemplate(\n input: TemplateCreateInput,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return createTemplate(this.getRuntimeContext(), input, ctx);\n }\n\n async updateTemplate(\n code: string,\n patch: TemplateUpdateInput,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return updateTemplate(this.getRuntimeContext(), code, patch, ctx);\n }\n\n async deleteTemplate(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n return deleteTemplate(this.getRuntimeContext(), code, ctx);\n }\n\n async getTemplate(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return getTemplate(this.getRuntimeContext(), code, ctx);\n }\n\n async listTemplates(\n params?: { status?: string; page?: number; limit?: number },\n ctx?: TemplateContext,\n ): Promise<Result<Template[], KMsgError>> {\n return listTemplates(this.getRuntimeContext(), params, ctx);\n }\n\n async requestTemplateInspection(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n return requestTemplateInspection(this.getRuntimeContext(), code, ctx);\n }\n}\n\nexport const createAligoProvider = (config: AligoConfig) =>\n new AligoProvider(config);\n\nexport const createDefaultAligoProvider = () => {\n const config: AligoConfig = {\n apiKey: readRuntimeEnv(\"ALIGO_API_KEY\") || \"\",\n userId: readRuntimeEnv(\"ALIGO_USER_ID\") || \"\",\n senderKey: readRuntimeEnv(\"ALIGO_SENDER_KEY\") || \"\",\n sender: readRuntimeEnv(\"ALIGO_SENDER\") || \"\",\n friendtalkEndpoint: readRuntimeEnv(\"ALIGO_FRIENDTALK_ENDPOINT\"),\n testMode: readRuntimeEnv(\"NODE_ENV\") !== \"production\",\n debug: readRuntimeEnv(\"NODE_ENV\") === \"development\",\n };\n\n if (!config.apiKey || !config.userId) {\n throw new Error(\"ALIGO_API_KEY and ALIGO_USER_ID are required\");\n }\n\n return new AligoProvider(config);\n};\n\n// biome-ignore lint/complexity/noStaticOnlyClass: kept as a factory for convenience\nexport class AligoProviderFactory {\n static create(config: AligoConfig): AligoProvider {\n return new AligoProvider(config);\n }\n\n static createDefault(): AligoProvider {\n return createDefaultAligoProvider();\n }\n}\n\nexport function initializeAligo(): void {}\n",
|
|
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 fail,\n type KakaoCategoryEntry,\n type KakaoChannel,\n type KakaoChannelCategories,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport { mapAligoKakaoError } from \"./aligo.error\";\nimport { parseAligoDateTime } from \"./aligo.helpers\";\nimport { ensureAligoKakaoOk, requestAligo } from \"./aligo.http\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\n\nexport async function listKakaoChannels(\n ctx: AligoRuntimeContext,\n params?: {\n plusId?: string;\n senderKey?: string;\n },\n): Promise<Result<KakaoChannel[], KMsgError>> {\n try {\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n ...(typeof params?.plusId === \"string\" && params.plusId.trim().length > 0\n ? { plusid: params.plusId.trim() }\n : {}),\n ...(typeof params?.senderKey === \"string\" &&\n params.senderKey.trim().length > 0\n ? { senderkey: params.senderKey.trim() }\n : {}),\n };\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/list/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const channels: KakaoChannel[] = list\n .filter(isObjectRecord)\n .map((item) => ({\n providerId: ctx.providerId,\n senderKey: String(item.senderKey ?? \"\"),\n plusId: typeof item.uuid === \"string\" ? item.uuid : undefined,\n name: typeof item.name === \"string\" ? item.name : undefined,\n status: typeof item.status === \"string\" ? item.status : undefined,\n createdAt: parseAligoDateTime(item.cdate),\n updatedAt: parseAligoDateTime(item.udate),\n raw: item,\n }))\n .filter((channel) => channel.senderKey.length > 0);\n\n return ok(channels);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function listKakaoChannelCategories(\n ctx: AligoRuntimeContext,\n): Promise<Result<KakaoChannelCategories, KMsgError>> {\n try {\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/category/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"category list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const data = isObjectRecord(response.data) ? response.data : {};\n\n const mapEntries = (raw: unknown): KakaoCategoryEntry[] => {\n const arr = Array.isArray(raw) ? raw : [];\n return arr\n .filter(isObjectRecord)\n .map((entry) => ({\n code: String(entry.code ?? \"\"),\n name: String(entry.name ?? \"\"),\n parentCode:\n typeof entry.parentCode === \"string\" && entry.parentCode.length > 0\n ? entry.parentCode\n : undefined,\n }))\n .filter((entry) => entry.code.length > 0);\n };\n\n return ok({\n first: mapEntries(data.firstBusinessType),\n second: mapEntries(data.secondBusinessType),\n third: mapEntries(data.thirdBusinessType),\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function requestKakaoChannelAuth(\n ctx: AligoRuntimeContext,\n params: {\n plusId: string;\n phoneNumber: string;\n },\n): Promise<Result<void, KMsgError>> {\n try {\n const plusId = params.plusId.trim();\n const phoneNumber = params.phoneNumber.trim();\n if (!plusId || !phoneNumber) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"plusId and phoneNumber are required\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/auth/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n plusid: plusId,\n phonenumber: phoneNumber,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel auth failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function addKakaoChannel(\n ctx: AligoRuntimeContext,\n params: {\n plusId: string;\n authNum: string;\n phoneNumber: string;\n categoryCode: string;\n },\n): Promise<Result<KakaoChannel, KMsgError>> {\n try {\n const plusId = params.plusId.trim();\n const authNum = params.authNum.trim();\n const phoneNumber = params.phoneNumber.trim();\n const categoryCode = params.categoryCode.trim();\n\n if (!plusId || !authNum || !phoneNumber || !categoryCode) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"plusId, authNum, phoneNumber, categoryCode are required\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/add/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n plusid: plusId,\n authnum: authNum,\n phonenumber: phoneNumber,\n categorycode: categoryCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel add failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const dataRaw = response.data;\n const data = Array.isArray(dataRaw)\n ? dataRaw.find(isObjectRecord)\n : isObjectRecord(dataRaw)\n ? dataRaw\n : undefined;\n\n if (!data) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"channel add returned empty data\",\n {\n providerId: ctx.providerId,\n raw: response,\n },\n ),\n );\n }\n\n const senderKey = String(data.senderKey ?? \"\");\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"channel add did not return senderKey\",\n { providerId: ctx.providerId, raw: data },\n ),\n );\n }\n\n return ok({\n providerId: ctx.providerId,\n senderKey,\n plusId: typeof data.uuid === \"string\" ? data.uuid : plusId,\n name: typeof data.name === \"string\" ? data.name : undefined,\n status: typeof data.status === \"string\" ? data.status : undefined,\n createdAt: parseAligoDateTime(data.cdate),\n updatedAt: parseAligoDateTime(data.udate),\n raw: data,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n",
|
|
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",
|
|
9
|
-
"import { KMsgError, KMsgErrorCode } from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\n\nexport function mapAligoKakaoError(\n error: unknown,\n providerId: string,\n): KMsgError {\n if (error instanceof KMsgError) return error;\n return new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n );\n}\n\nexport function mapAligoError(error: unknown, providerId: string): KMsgError {\n if (error instanceof KMsgError) return error;\n\n const record = isObjectRecord(error) ? error : {};\n const resultCodeRaw = record.result_code;\n const resultCode =\n resultCodeRaw !== undefined && resultCodeRaw !== null\n ? String(resultCodeRaw)\n : \"UNKNOWN\";\n\n const message =\n typeof record.message === \"string\" && record.message.length > 0\n ? record.message\n : typeof record.msg === \"string\" && record.msg.length > 0\n ? record.msg\n : error instanceof Error\n ? error.message\n : \"Unknown Aligo error\";\n\n let code: KMsgErrorCode = KMsgErrorCode.PROVIDER_ERROR;\n\n switch (resultCode) {\n case \"-100\":\n case \"-101\":\n code = KMsgErrorCode.AUTHENTICATION_FAILED;\n break;\n case \"-102\":\n case \"-201\":\n code = KMsgErrorCode.INSUFFICIENT_BALANCE;\n break;\n case \"-103\":\n case \"-105\":\n code = KMsgErrorCode.INVALID_REQUEST;\n break;\n case \"-501\":\n code = KMsgErrorCode.TEMPLATE_NOT_FOUND;\n break;\n default:\n code = KMsgErrorCode.PROVIDER_ERROR;\n }\n\n return new KMsgError(code, `${message} (code: ${resultCode})`, {\n providerId,\n resultCode,\n });\n}\n",
|
|
10
|
-
"import {\n KMsgError,\n KMsgErrorCode,\n type MessageBinaryInput,\n type Template,\n type TemplateContext,\n} from \"@k-msg/core\";\nimport {\n ButtonParser,\n interpolate,\n type TemplateButton,\n} from \"@k-msg/template\";\nimport type { AligoConfig } from \"./types/aligo\";\n\nexport function resolveImageRef(options: {\n imageUrl?: string;\n media?: { image?: MessageBinaryInput };\n providerId: string;\n}): string | undefined {\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 \"Aligo MMS/FriendTalk image requires `options.imageUrl` or `options.media.image.ref` (url/path).\",\n { providerId: options.providerId },\n );\n}\n\nexport function getAligoEndpoint(\n operation: \"sendSMS\" | \"sendAlimTalk\" | \"sendFriendTalk\",\n config: AligoConfig,\n): string {\n switch (operation) {\n case \"sendSMS\":\n return \"/send/\";\n case \"sendAlimTalk\":\n return \"/akv10/alimtalk/send/\";\n case \"sendFriendTalk\":\n return config.friendtalkEndpoint || \"/akv10/friendtalk/send/\";\n default:\n return \"/\";\n }\n}\n\nexport function formatAligoDate(date: Date): { date: string; time: string } {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n\n return {\n date: `${year}${month}${day}`,\n time: `${hours}${minutes}`,\n };\n}\n\nexport function normalizeAligoKakaoCode(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n const num = Number(trimmed);\n if (Number.isFinite(num)) return num;\n }\n return undefined;\n}\n\nexport function resolveKakaoSenderKey(\n params: {\n providerId: string;\n config: AligoConfig;\n },\n ctx?: TemplateContext,\n): string {\n const senderKey =\n (typeof ctx?.kakaoChannelSenderKey === \"string\" &&\n ctx.kakaoChannelSenderKey.trim().length > 0\n ? ctx.kakaoChannelSenderKey.trim()\n : params.config.senderKey) || \"\";\n if (!senderKey) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao channel senderKey is required (ctx.kakaoChannelSenderKey or config.senderKey)\",\n { providerId: params.providerId },\n );\n }\n return senderKey;\n}\n\nexport function toAligoTplButton(\n buttons: TemplateButton[] | undefined,\n): string | undefined {\n if (!Array.isArray(buttons) || buttons.length === 0) return undefined;\n\n const serializedButtons = JSON.parse(\n ButtonParser.serializeButtons(buttons),\n ) as unknown[];\n return JSON.stringify({ button: serializedButtons });\n}\n\nexport function mapAligoTemplateStatus(\n item: Record<string, unknown>,\n): Template[\"status\"] {\n const insp =\n typeof item.inspStatus === \"string\"\n ? item.inspStatus.trim().toUpperCase()\n : \"\";\n switch (insp) {\n case \"APR\":\n return \"APPROVED\";\n case \"REJ\":\n return \"REJECTED\";\n case \"REQ\":\n case \"REG\":\n return \"INSPECTION\";\n default:\n return \"PENDING\";\n }\n}\n\nexport function parseAligoDateTime(value: unknown): Date | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})\\s+(\\d{2}):(\\d{2}):(\\d{2})$/.exec(\n trimmed,\n );\n if (!match) return undefined;\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const hour = Number(match[4]);\n const minute = Number(match[5]);\n const second = Number(match[6]);\n\n const date = new Date(year, month - 1, day, hour, minute, second);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\nexport function resolveAligoTemplateMessage(\n variables: Record<string, unknown> | undefined,\n templateContent?: string,\n): string {\n if (!variables) return \"\";\n const fullText = variables._full_text;\n if (fullText !== undefined && fullText !== null) return String(fullText);\n if (!templateContent) return Object.values(variables).map(String).join(\"\\n\");\n\n return interpolate(templateContent, variables);\n}\n",
|
|
11
|
-
"import { fail, KMsgError, KMsgErrorCode, ok, type Result } from \"@k-msg/core\";\nimport { normalizeAligoKakaoCode } from \"./aligo.helpers\";\n\nexport async function requestAligo(params: {\n host: string;\n endpoint: string;\n data: Record<string, unknown>;\n providerId: string;\n}): Promise<Record<string, unknown>> {\n const formData = new FormData();\n for (const [key, value] of Object.entries(params.data)) {\n if (value !== undefined && value !== null) {\n formData.append(key, String(value));\n }\n }\n\n const response = await fetch(`${params.host}${params.endpoint}`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n throw new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n `HTTP error! status: ${response.status}`,\n { providerId: params.providerId },\n );\n }\n\n return (await response.json()) as Record<string, unknown>;\n}\n\nexport function ensureAligoKakaoOk(params: {\n providerId: string;\n response: Record<string, unknown>;\n fallbackMessage: string;\n}): Result<void, KMsgError> {\n const { providerId, response, fallbackMessage } = params;\n const rawCode = response.code;\n const code = normalizeAligoKakaoCode(rawCode);\n if (code === 0) return ok(undefined);\n\n const message =\n typeof response.message === \"string\" && response.message.length > 0\n ? response.message\n : fallbackMessage;\n const mapped =\n code === 509 || code === -99\n ? KMsgErrorCode.INVALID_REQUEST\n : KMsgErrorCode.PROVIDER_ERROR;\n return fail(\n new KMsgError(mapped, message, {\n providerId,\n originalCode: rawCode,\n raw: response,\n }),\n );\n}\n",
|
|
12
|
-
"import {\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n type SendOptions,\n type SendResult,\n} from \"@k-msg/core\";\nimport { mapAligoError } from \"./aligo.error\";\nimport {\n formatAligoDate,\n getAligoEndpoint,\n resolveAligoTemplateMessage,\n resolveImageRef,\n} from \"./aligo.helpers\";\nimport { requestAligo } from \"./aligo.http\";\nimport type {\n AligoMessageType,\n AligoRuntimeContext,\n} from \"./aligo.internal.types\";\nimport type { AligoResponse, AligoSMSRequest } from \"./types/aligo\";\n\nexport function collectSendWarnings(\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 \"Aligo failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.\",\n details: {\n providerId,\n mappedFields: [\"failover\", \"fmessage_1\", \"fsubject_1\"],\n unsupportedFields: [\"fallbackChannel\"],\n },\n },\n ];\n}\n\nasync function sendSMS(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"SMS\" | \"LMS\" | \"MMS\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for SMS/LMS/MMS (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const body: AligoSMSRequest = {\n key: ctx.config.apiKey,\n user_id: ctx.config.userId,\n sender,\n receiver: options.to,\n msg: options.text,\n msg_type: options.type,\n title: options.subject,\n testmode_yn: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.rdate = date;\n body.rtime = time;\n }\n\n if (options.type === \"MMS\") {\n const imageRef = resolveImageRef({\n imageUrl: options.imageUrl,\n media: options.media,\n providerId: ctx.providerId,\n });\n if (!imageRef) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"image is required for MMS (options.imageUrl or options.media.image.ref)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n body.image = imageRef;\n }\n\n const response = (await requestAligo({\n host: ctx.smsHost,\n endpoint: getAligoEndpoint(\"sendSMS\", ctx.config),\n data: body as unknown as Record<string, unknown>,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"1\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n raw: response,\n });\n}\n\nasync function sendAlimTalk(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"ALIMTALK\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const warnings = collectSendWarnings(options, ctx.providerId);\n const senderKey =\n (typeof options.kakao?.profileId === \"string\"\n ? options.kakao.profileId\n : ctx.config.senderKey) || \"\";\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.senderKey)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for ALIMTALK (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const variables = options.variables as Record<string, unknown>;\n const templateId = options.templateId;\n if (!templateId || templateId.length === 0) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"templateId is required for ALIMTALK\",\n { providerId: ctx.providerId },\n ),\n );\n }\n const templateContent =\n typeof options.providerOptions?.templateContent === \"string\"\n ? options.providerOptions.templateContent\n : undefined;\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateId,\n sender,\n receiver_1: options.to,\n subject_1: \"알림톡\",\n message_1: resolveAligoTemplateMessage(variables, templateContent),\n testMode: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const failoverOverrideRaw =\n typeof options.providerOptions?.failover === \"string\"\n ? options.providerOptions.failover.trim().toUpperCase()\n : \"\";\n const failoverOverride =\n failoverOverrideRaw === \"Y\" || failoverOverrideRaw === \"N\"\n ? failoverOverrideRaw\n : undefined;\n const failoverFromOptions =\n options.failover?.enabled === true\n ? \"Y\"\n : options.failover?.enabled === false\n ? \"N\"\n : undefined;\n const failover = failoverOverride ?? failoverFromOptions;\n\n const fallbackTitle =\n typeof options.providerOptions?.fsubject_1 === \"string\" &&\n options.providerOptions.fsubject_1.trim().length > 0\n ? options.providerOptions.fsubject_1.trim()\n : typeof options.failover?.fallbackTitle === \"string\" &&\n options.failover.fallbackTitle.trim().length > 0\n ? options.failover.fallbackTitle.trim()\n : undefined;\n const fallbackContent =\n typeof options.providerOptions?.fmessage_1 === \"string\" &&\n options.providerOptions.fmessage_1.trim().length > 0\n ? options.providerOptions.fmessage_1.trim()\n : typeof options.failover?.fallbackContent === \"string\" &&\n options.failover.fallbackContent.trim().length > 0\n ? options.failover.fallbackContent.trim()\n : undefined;\n\n if (failover) {\n body.failover = failover;\n }\n if (fallbackTitle) {\n body.fsubject_1 = fallbackTitle;\n }\n if (fallbackContent) {\n body.fmessage_1 = fallbackContent;\n }\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.reserve = \"Y\";\n body.reserve_date = date;\n body.reserve_time = time;\n }\n\n const response = (await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: getAligoEndpoint(\"sendAlimTalk\", ctx.config),\n data: body,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"0\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n ...(Array.isArray(warnings) && warnings.length > 0 ? { warnings } : {}),\n raw: response,\n });\n}\n\nasync function sendFriendTalk(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"FRIENDTALK\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const senderKey =\n (typeof options.kakao?.profileId === \"string\"\n ? options.kakao.profileId\n : ctx.config.senderKey) || \"\";\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.senderKey)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for FRIENDTALK (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n sender,\n receiver_1: options.to,\n subject_1: \"친구톡\",\n message_1: options.text,\n testMode: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const imageRef = resolveImageRef({\n imageUrl: options.imageUrl,\n media: options.media,\n providerId: ctx.providerId,\n });\n if (imageRef) {\n body.image_1 = imageRef;\n }\n\n const buttons = Array.isArray(options.kakao?.buttons)\n ? options.kakao.buttons\n : options.buttons;\n if (buttons) {\n body.button_1 = JSON.stringify(buttons);\n }\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.reserve = \"Y\";\n body.reserve_date = date;\n body.reserve_time = time;\n }\n\n const response = (await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: getAligoEndpoint(\"sendFriendTalk\", ctx.config),\n data: body,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"0\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n raw: response,\n });\n}\n\nexport async function sendWithAligo(\n ctx: AligoRuntimeContext,\n options: SendOptions,\n): Promise<Result<SendResult, KMsgError>> {\n try {\n switch (options.type as AligoMessageType) {\n case \"ALIMTALK\":\n return await sendAlimTalk(\n ctx,\n options as Extract<SendOptions, { type: \"ALIMTALK\" }>,\n );\n case \"FRIENDTALK\":\n return await sendFriendTalk(\n ctx,\n options as Extract<SendOptions, { type: \"FRIENDTALK\" }>,\n );\n case \"SMS\":\n case \"LMS\":\n case \"MMS\":\n return await sendSMS(\n ctx,\n options as Extract<SendOptions, { type: \"SMS\" | \"LMS\" | \"MMS\" }>,\n );\n default:\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `AligoProvider does not support type ${options.type}`,\n { providerId: ctx.providerId, type: options.type },\n ),\n );\n }\n } catch (error) {\n return fail(mapAligoError(error, ctx.providerId));\n }\n}\n",
|
|
13
|
-
"import {\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n type Template,\n type TemplateContext,\n type TemplateCreateInput,\n type TemplateUpdateInput,\n} from \"@k-msg/core\";\nimport { validateTemplatePayload } from \"@k-msg/template\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport { mapAligoKakaoError } from \"./aligo.error\";\nimport {\n mapAligoTemplateStatus,\n parseAligoDateTime,\n resolveKakaoSenderKey,\n toAligoTplButton,\n} from \"./aligo.helpers\";\nimport { ensureAligoKakaoOk, requestAligo } from \"./aligo.http\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\n\nfunction withProviderContext(error: KMsgError, providerId: string): KMsgError {\n return new KMsgError(error.code, error.message, {\n providerId,\n ...(error.details ?? {}),\n });\n}\n\nexport async function createTemplate(\n ctx: AligoRuntimeContext,\n input: TemplateCreateInput,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const payloadValidation = validateTemplatePayload(input, {\n requireName: true,\n requireContent: true,\n });\n if (payloadValidation.isFailure) {\n return fail(withProviderContext(payloadValidation.error, ctx.providerId));\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_name: payloadValidation.value.name ?? input.name,\n tpl_content: payloadValidation.value.content ?? input.content,\n };\n\n const tplButton = toAligoTplButton(payloadValidation.value.buttons);\n if (tplButton) body.tpl_button = tplButton;\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/add/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template create failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const data = isObjectRecord(response.data) ? response.data : {};\n const code = String(data.templtCode ?? \"\");\n if (!code) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"template create did not return templtCode\",\n { providerId: ctx.providerId, raw: response },\n ),\n );\n }\n\n const createdAt = parseAligoDateTime(data.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(data.udate) ??\n parseAligoDateTime(data.cdate) ??\n createdAt;\n\n return ok({\n id: code,\n code,\n name: String(\n data.templtName ?? payloadValidation.value.name ?? input.name,\n ),\n content: String(\n data.templtContent ?? payloadValidation.value.content ?? input.content,\n ),\n category: input.category,\n status: mapAligoTemplateStatus(data),\n buttons: Array.isArray(data.buttons)\n ? data.buttons\n : payloadValidation.value.buttons,\n variables: input.variables,\n createdAt,\n updatedAt,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function getTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/list/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template get failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const first = list.find(isObjectRecord);\n if (!first) {\n return fail(\n new KMsgError(KMsgErrorCode.TEMPLATE_NOT_FOUND, \"Template not found\", {\n providerId: ctx.providerId,\n templateCode,\n }),\n );\n }\n\n const tplCode = String(first.templtCode ?? templateCode);\n const createdAt = parseAligoDateTime(first.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(first.udate) ??\n parseAligoDateTime(first.cdate) ??\n createdAt;\n\n return ok({\n id: tplCode,\n code: tplCode,\n name: String(first.templtName ?? \"\"),\n content: String(first.templtContent ?? \"\"),\n status: mapAligoTemplateStatus(first),\n buttons: Array.isArray(first.buttons) ? first.buttons : undefined,\n createdAt,\n updatedAt,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function updateTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n patch: TemplateUpdateInput,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const existingResult = await getTemplate(ctx, templateCode, {\n kakaoChannelSenderKey: senderKey,\n });\n if (existingResult.isFailure) return existingResult;\n const existing = existingResult.value;\n\n const nextName =\n typeof patch.name === \"string\" && patch.name.trim().length > 0\n ? patch.name.trim()\n : existing.name;\n const nextContent =\n typeof patch.content === \"string\" && patch.content.trim().length > 0\n ? patch.content\n : existing.content;\n const payloadValidation = validateTemplatePayload(\n {\n name: nextName,\n content: nextContent,\n buttons: patch.buttons !== undefined ? patch.buttons : existing.buttons,\n },\n {\n requireName: true,\n requireContent: true,\n },\n );\n if (payloadValidation.isFailure) {\n return fail(withProviderContext(payloadValidation.error, ctx.providerId));\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n tpl_name: payloadValidation.value.name ?? nextName,\n tpl_content: payloadValidation.value.content ?? nextContent,\n };\n\n const tplButton = toAligoTplButton(payloadValidation.value.buttons);\n if (tplButton) body.tpl_button = tplButton;\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/modify/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template update failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const refreshed = await getTemplate(ctx, templateCode, {\n kakaoChannelSenderKey: senderKey,\n });\n if (refreshed.isSuccess) return refreshed;\n\n return ok({\n ...existing,\n name: payloadValidation.value.name ?? nextName,\n content: payloadValidation.value.content ?? nextContent,\n ...(patch.category !== undefined ? { category: patch.category } : {}),\n ...(patch.variables !== undefined ? { variables: patch.variables } : {}),\n ...(patch.buttons !== undefined\n ? { buttons: payloadValidation.value.buttons }\n : {}),\n updatedAt: new Date(),\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function deleteTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<void, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/del/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template delete failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function listTemplates(\n ctx: AligoRuntimeContext,\n params?: { status?: string; page?: number; limit?: number },\n templateCtx?: TemplateContext,\n): Promise<Result<Template[], KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/list/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const templates = list\n .filter(isObjectRecord)\n .map((item) => {\n const tplCode = String(item.templtCode ?? \"\");\n const createdAt = parseAligoDateTime(item.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(item.udate) ??\n parseAligoDateTime(item.cdate) ??\n createdAt;\n\n return {\n id: tplCode,\n code: tplCode,\n name: String(item.templtName ?? \"\"),\n content: String(item.templtContent ?? \"\"),\n status: mapAligoTemplateStatus(item),\n buttons: Array.isArray(item.buttons) ? item.buttons : undefined,\n createdAt,\n updatedAt,\n } satisfies Template;\n })\n .filter((template) => template.code.length > 0);\n\n if (params?.status) {\n const status = params.status.trim().toUpperCase();\n return ok(templates.filter((template) => template.status === status));\n }\n\n return ok(templates);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function requestTemplateInspection(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<void, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/request/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template inspection request failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n"
|
|
14
|
-
],
|
|
15
|
-
"mappings": "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",
|
|
16
|
-
"debugId": "712B4D075ED82CEB64756E2164756E21",
|
|
17
|
-
"names": []
|
|
18
|
-
}
|