UNPKG

@k-msg/provider

Version:

Complete provider system with adapters and implementations for K-Message platform

6 lines (4 loc) 20.1 kB
var{defineProperty:M,getOwnPropertyNames:x,getOwnPropertyDescriptor:ee}=Object,re=Object.prototype.hasOwnProperty;var q=new WeakMap,te=(e)=>{var r=q.get(e),t;if(r)return r;if(r=M({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")x(e).map((n)=>!re.call(r,n)&&M(r,n,{get:()=>e[n],enumerable:!(t=ee(e,n))||t.enumerable}));return q.set(e,r),r};var ne=(e,r)=>{for(var t in r)M(e,t,{get:r[t],enumerable:!0,configurable:!0,set:(n)=>r[t]=()=>n})};var ce={};ne(ce,{createDefaultAligoSendProvider:()=>_,createDefaultAligoProvider:()=>_,createAligoSendProvider:()=>C,createAligoProvider:()=>C,AligoSendProviderFactory:()=>P,AligoSendProvider:()=>v,AligoProvider:()=>v});module.exports=te(ce);var y=require("@k-msg/core");var V={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 F(e){return V[e]}function Ie(){return Object.values(V)}var p=require("@k-msg/core");function I(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}var f=require("@k-msg/core");function A(e,r){if(e instanceof f.KMsgError)return e;return new f.KMsgError(f.KMsgErrorCode.PROVIDER_ERROR,e instanceof Error?e.message:String(e),{providerId:r})}function R(e,r){if(e instanceof f.KMsgError)return e;let t=I(e)?e:{},n=t.result_code,i=n!==void 0&&n!==null?String(n):"UNKNOWN",a=typeof t.message==="string"&&t.message.length>0?t.message:typeof t.msg==="string"&&t.msg.length>0?t.msg:e instanceof Error?e.message:"Unknown Aligo error",d=f.KMsgErrorCode.PROVIDER_ERROR;switch(i){case"-100":case"-101":d=f.KMsgErrorCode.AUTHENTICATION_FAILED;break;case"-102":case"-201":d=f.KMsgErrorCode.INSUFFICIENT_BALANCE;break;case"-103":case"-105":d=f.KMsgErrorCode.INVALID_REQUEST;break;case"-501":d=f.KMsgErrorCode.TEMPLATE_NOT_FOUND;break;default:d=f.KMsgErrorCode.PROVIDER_ERROR}return new f.KMsgError(d,`${a} (code: ${i})`,{providerId:r,resultCode:i})}var g=require("@k-msg/core");var c=require("@k-msg/core");function ie(e){if(typeof DOMException<"u"&&e instanceof DOMException&&e.name==="TimeoutError")return!0;return typeof e==="object"&&e!==null&&"code"in e&&e.code===c.KMsgErrorCode.NETWORK_TIMEOUT}function oe(e){return typeof DOMException<"u"&&e instanceof DOMException&&e.name==="AbortError"}function ae(e){if(e instanceof Error)return e.message;if(typeof e==="string"&&e.length>0)return e;return"Provider request aborted"}function se(e,r,t){if(!r?.aborted)return;if(e instanceof c.KMsgError)return e;let n=r.reason??e,i=oe(n)?e:n;return new c.KMsgError(ie(n)?c.KMsgErrorCode.NETWORK_TIMEOUT:c.KMsgErrorCode.REQUEST_ABORTED,ae(i),{providerId:t})}function j(e,r){if(e instanceof c.KMsgError)return e;return new c.KMsgError(c.KMsgErrorCode.NETWORK_ERROR,e instanceof Error?e.message:String(e),{providerId:r})}function N(e,r,t){return se(e,r,t)??j(e,t)}async function Q(e,r,t,n){let i=e?.fetch??globalThis.fetch;if(typeof i!=="function")throw j(Error("No fetch implementation is available; provide ProviderRequestContext.fetch or use a runtime with native fetch support"),n);try{return await i(r,{...t,signal:e?.signal})}catch(a){throw N(a,e?.signal,n)}}var h=require("@k-msg/core");function de(e,r){if(!e)return"";return e.replace(/#\{([^}]+)\}/g,(t,n)=>{let i=r[n];return i===void 0||i===null?t:String(i)})}function O(e){let r=typeof e.imageUrl==="string"&&e.imageUrl.trim().length>0?e.imageUrl.trim():void 0;if(r)return r;let t=e.media?.image;if(!t)return;if("ref"in t){let n=t.ref.trim();return n.length>0?n:void 0}throw new h.KMsgError(h.KMsgErrorCode.INVALID_REQUEST,"Aligo MMS/FriendTalk image requires `options.imageUrl` or `options.media.image.ref` (url/path).",{providerId:e.providerId})}function K(e,r){switch(e){case"sendSMS":return"/send/";case"sendAlimTalk":return"/akv10/alimtalk/send/";case"sendFriendTalk":return r.friendtalkEndpoint||"/akv10/friendtalk/send/";default:return"/"}}function T(e){let r=e.getFullYear(),t=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0"),i=String(e.getHours()).padStart(2,"0"),a=String(e.getMinutes()).padStart(2,"0");return{date:`${r}${t}${n}`,time:`${i}${a}`}}function W(e){if(typeof e==="number"&&Number.isFinite(e))return e;if(typeof e==="string"){let r=e.trim();if(!r)return;let t=Number(r);if(Number.isFinite(t))return t}return}function Re(e,r){let t=(typeof r?.kakaoChannelSenderKey==="string"&&r.kakaoChannelSenderKey.trim().length>0?r.kakaoChannelSenderKey.trim():e.config.senderKey)||"";if(!t)throw new h.KMsgError(h.KMsgErrorCode.INVALID_REQUEST,"kakao channel senderKey is required (ctx.kakaoChannelSenderKey or config.senderKey)",{providerId:e.providerId});return t}function be(e){switch(typeof e.inspStatus==="string"?e.inspStatus.trim().toUpperCase():""){case"APR":return"APPROVED";case"REJ":return"REJECTED";case"REQ":case"REG":return"INSPECTION";default:return"PENDING"}}function b(e){if(typeof e!=="string")return;let r=e.trim();if(!r)return;let t=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/.exec(r);if(!t)return;let n=Number(t[1]),i=Number(t[2]),a=Number(t[3]),d=Number(t[4]),l=Number(t[5]),s=Number(t[6]),u=new Date(n,i-1,a,d,l,s);return Number.isNaN(u.getTime())?void 0:u}function $(e,r){if(!e)return"";let t=e._full_text;if(t!==void 0&&t!==null)return String(t);if(!r)return Object.values(e).map(String).join(` `);return de(r,e)}async function m(e){let r=new FormData;for(let[t,n]of Object.entries(e.data))if(n!==void 0&&n!==null)r.append(t,String(n));try{let t=await Q(e.context,`${e.host}${e.endpoint}`,{method:"POST",body:r},e.providerId);if(!t.ok)throw new g.KMsgError(g.KMsgErrorCode.NETWORK_ERROR,`HTTP error! status: ${t.status}`,{providerId:e.providerId});return await t.json()}catch(t){throw N(t,e.context?.signal,e.providerId)}}function E(e){let{providerId:r,response:t,fallbackMessage:n}=e,i=t.code,a=W(i);if(a===0)return g.ok(void 0);let d=typeof t.message==="string"&&t.message.length>0?t.message:n,l=a===509||a===-99?g.KMsgErrorCode.INVALID_REQUEST:g.KMsgErrorCode.PROVIDER_ERROR;return g.fail(new g.KMsgError(l,d,{providerId:r,originalCode:i,raw:t}))}async function H(e,r){try{let t={apikey:e.config.apiKey,userid:e.config.userId,...typeof r?.plusId==="string"&&r.plusId.trim().length>0?{plusid:r.plusId.trim()}:{},...typeof r?.senderKey==="string"&&r.senderKey.trim().length>0?{senderkey:r.senderKey.trim()}:{}},n=await m({host:e.alimtalkHost,endpoint:"/akv10/profile/list/",data:t,providerId:e.providerId}),i=E({providerId:e.providerId,response:n,fallbackMessage:"channel list failed"});if(i.isFailure)return i;let a=n.list,l=(Array.isArray(a)?a:[]).filter(I).map((s)=>({providerId:e.providerId,senderKey:String(s.senderKey??""),plusId:typeof s.uuid==="string"?s.uuid:void 0,name:typeof s.name==="string"?s.name:void 0,status:typeof s.status==="string"?s.status:void 0,createdAt:b(s.cdate),updatedAt:b(s.udate),raw:s})).filter((s)=>s.senderKey.length>0);return p.ok(l)}catch(t){return p.fail(A(t,e.providerId))}}async function Y(e){try{let r=await m({host:e.alimtalkHost,endpoint:"/akv10/category/",data:{apikey:e.config.apiKey,userid:e.config.userId},providerId:e.providerId}),t=E({providerId:e.providerId,response:r,fallbackMessage:"category list failed"});if(t.isFailure)return t;let n=I(r.data)?r.data:{},i=(a)=>{return(Array.isArray(a)?a:[]).filter(I).map((l)=>({code:String(l.code??""),name:String(l.name??""),parentCode:typeof l.parentCode==="string"&&l.parentCode.length>0?l.parentCode:void 0})).filter((l)=>l.code.length>0)};return p.ok({first:i(n.firstBusinessType),second:i(n.secondBusinessType),third:i(n.thirdBusinessType)})}catch(r){return p.fail(A(r,e.providerId))}}async function B(e,r){try{let t=r.plusId.trim(),n=r.phoneNumber.trim();if(!t||!n)return p.fail(new p.KMsgError(p.KMsgErrorCode.INVALID_REQUEST,"plusId and phoneNumber are required",{providerId:e.providerId}));let i=await m({host:e.alimtalkHost,endpoint:"/akv10/profile/auth/",data:{apikey:e.config.apiKey,userid:e.config.userId,plusid:t,phonenumber:n},providerId:e.providerId}),a=E({providerId:e.providerId,response:i,fallbackMessage:"channel auth failed"});if(a.isFailure)return a;return p.ok(void 0)}catch(t){return p.fail(A(t,e.providerId))}}async function G(e,r){try{let t=r.plusId.trim(),n=r.authNum.trim(),i=r.phoneNumber.trim(),a=r.categoryCode.trim();if(!t||!n||!i||!a)return p.fail(new p.KMsgError(p.KMsgErrorCode.INVALID_REQUEST,"plusId, authNum, phoneNumber, categoryCode are required",{providerId:e.providerId}));let d=await m({host:e.alimtalkHost,endpoint:"/akv10/profile/add/",data:{apikey:e.config.apiKey,userid:e.config.userId,plusid:t,authnum:n,phonenumber:i,categorycode:a},providerId:e.providerId}),l=E({providerId:e.providerId,response:d,fallbackMessage:"channel add failed"});if(l.isFailure)return l;let s=d.data,u=Array.isArray(s)?s.find(I):I(s)?s:void 0;if(!u)return p.fail(new p.KMsgError(p.KMsgErrorCode.PROVIDER_ERROR,"channel add returned empty data",{providerId:e.providerId,raw:d}));let k=String(u.senderKey??"");if(!k)return p.fail(new p.KMsgError(p.KMsgErrorCode.PROVIDER_ERROR,"channel add did not return senderKey",{providerId:e.providerId,raw:u}));return p.ok({providerId:e.providerId,senderKey:k,plusId:typeof u.uuid==="string"?u.uuid:t,name:typeof u.name==="string"?u.name:void 0,status:typeof u.status==="string"?u.status:void 0,createdAt:b(u.cdate),updatedAt:b(u.udate),raw:u})}catch(t){return p.fail(A(t,e.providerId))}}var o=require("@k-msg/core");function le(e,r){if(e.type!=="ALIMTALK")return;if(e.failover?.enabled!==!0)return;return[{code:"FAILOVER_PARTIAL_PROVIDER",message:"Aligo failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.",details:{providerId:r,mappedFields:["failover","fmessage_1","fsubject_1"],unsupportedFields:["fallbackChannel"]}}]}async function pe(e,r){let t=r.from||e.config.sender||"";if(!t)return o.fail(new o.KMsgError(o.KMsgErrorCode.INVALID_REQUEST,"from is required for SMS/LMS/MMS (options.from or config.sender)",{providerId:e.providerId}));let n={key:e.config.apiKey,user_id:e.config.userId,sender:t,receiver:r.to,msg:r.text,msg_type:r.type,title:r.subject,testmode_yn:e.config.testMode?"Y":"N"},i=r.options?.scheduledAt;if(i instanceof Date&&!Number.isNaN(i.getTime())){let{date:d,time:l}=T(i);n.rdate=d,n.rtime=l}if(r.type==="MMS"){let d=O({imageUrl:r.imageUrl,media:r.media,providerId:e.providerId});if(!d)return o.fail(new o.KMsgError(o.KMsgErrorCode.INVALID_REQUEST,"image is required for MMS (options.imageUrl or options.media.image.ref)",{providerId:e.providerId}));n.image=d}let a=await m({host:e.smsHost,endpoint:K("sendSMS",e.config),data:n,providerId:e.providerId,context:e.requestContext});if(a.result_code!=="1")return o.fail(R(a,e.providerId));return o.ok({messageId:r.messageId||crypto.randomUUID(),providerId:e.providerId,providerMessageId:a.msg_id,status:"PENDING",type:r.type,to:r.to,raw:a})}async function ue(e,r){let t=le(r,e.providerId),n=(typeof r.kakao?.profileId==="string"?r.kakao.profileId:e.config.senderKey)||"";if(!n)return o.fail(new o.KMsgError(o.KMsgErrorCode.INVALID_REQUEST,"kakao profileId is required (options.kakao.profileId or config.senderKey)",{providerId:e.providerId}));let i=r.from||e.config.sender||"";if(!i)return o.fail(new o.KMsgError(o.KMsgErrorCode.INVALID_REQUEST,"from is required for ALIMTALK (options.from or config.sender)",{providerId:e.providerId}));let{variables:a,templateId:d}=r;if(!d||d.length===0)return o.fail(new o.KMsgError(o.KMsgErrorCode.INVALID_REQUEST,"templateId is required for ALIMTALK",{providerId:e.providerId}));let l=typeof r.providerOptions?.templateContent==="string"?r.providerOptions.templateContent:void 0,s={apikey:e.config.apiKey,userid:e.config.userId,senderkey:n,tpl_code:d,sender:i,receiver_1:r.to,subject_1:"알림톡",message_1:$(a,l),testMode:e.config.testMode?"Y":"N"},u=typeof r.providerOptions?.failover==="string"?r.providerOptions.failover.trim().toUpperCase():"",k=u==="Y"||u==="N"?u:void 0,z=r.failover?.enabled===!0?"Y":r.failover?.enabled===!1?"N":void 0,D=k??z,L=typeof r.providerOptions?.fsubject_1==="string"&&r.providerOptions.fsubject_1.trim().length>0?r.providerOptions.fsubject_1.trim():typeof r.failover?.fallbackTitle==="string"&&r.failover.fallbackTitle.trim().length>0?r.failover.fallbackTitle.trim():void 0,U=typeof r.providerOptions?.fmessage_1==="string"&&r.providerOptions.fmessage_1.trim().length>0?r.providerOptions.fmessage_1.trim():typeof r.failover?.fallbackContent==="string"&&r.failover.fallbackContent.trim().length>0?r.failover.fallbackContent.trim():void 0;if(D)s.failover=D;if(L)s.fsubject_1=L;if(U)s.fmessage_1=U;let w=r.options?.scheduledAt;if(w instanceof Date&&!Number.isNaN(w.getTime())){let{date:X,time:Z}=T(w);s.reserve="Y",s.reserve_date=X,s.reserve_time=Z}let S=await m({host:e.alimtalkHost,endpoint:K("sendAlimTalk",e.config),data:s,providerId:e.providerId,context:e.requestContext});if(S.result_code!=="0")return o.fail(R(S,e.providerId));return o.ok({messageId:r.messageId||crypto.randomUUID(),providerId:e.providerId,providerMessageId:S.msg_id,status:"PENDING",type:r.type,to:r.to,...Array.isArray(t)&&t.length>0?{warnings:t}:{},raw:S})}async function fe(e,r){let t=(typeof r.kakao?.profileId==="string"?r.kakao.profileId:e.config.senderKey)||"";if(!t)return o.fail(new o.KMsgError(o.KMsgErrorCode.INVALID_REQUEST,"kakao profileId is required (options.kakao.profileId or config.senderKey)",{providerId:e.providerId}));let n=r.from||e.config.sender||"";if(!n)return o.fail(new o.KMsgError(o.KMsgErrorCode.INVALID_REQUEST,"from is required for FRIENDTALK (options.from or config.sender)",{providerId:e.providerId}));let i={apikey:e.config.apiKey,userid:e.config.userId,senderkey:t,sender:n,receiver_1:r.to,subject_1:"친구톡",message_1:r.text,testMode:e.config.testMode?"Y":"N"},a=O({imageUrl:r.imageUrl,media:r.media,providerId:e.providerId});if(a)i.image_1=a;let d=Array.isArray(r.kakao?.buttons)?r.kakao.buttons:r.buttons;if(d)i.button_1=JSON.stringify(d);let l=r.options?.scheduledAt;if(l instanceof Date&&!Number.isNaN(l.getTime())){let{date:u,time:k}=T(l);i.reserve="Y",i.reserve_date=u,i.reserve_time=k}let s=await m({host:e.alimtalkHost,endpoint:K("sendFriendTalk",e.config),data:i,providerId:e.providerId,context:e.requestContext});if(s.result_code!=="0")return o.fail(R(s,e.providerId));return o.ok({messageId:r.messageId||crypto.randomUUID(),providerId:e.providerId,providerMessageId:s.msg_id,status:"PENDING",type:r.type,to:r.to,raw:s})}async function J(e,r){try{switch(r.type){case"ALIMTALK":return await ue(e,r);case"FRIENDTALK":return await fe(e,r);case"SMS":case"LMS":case"MMS":return await pe(e,r);default:return o.fail(new o.KMsgError(o.KMsgErrorCode.INVALID_REQUEST,`AligoProvider does not support type ${r.type}`,{providerId:e.providerId,type:r.type}))}}catch(t){return o.fail(R(t,e.providerId))}}function ge(){return{apiKey:y.readRuntimeEnv("ALIGO_API_KEY")||"",userId:y.readRuntimeEnv("ALIGO_USER_ID")||"",senderKey:y.readRuntimeEnv("ALIGO_SENDER_KEY")||"",sender:y.readRuntimeEnv("ALIGO_SENDER")||"",friendtalkEndpoint:y.readRuntimeEnv("ALIGO_FRIENDTALK_ENDPOINT"),testMode:y.readRuntimeEnv("NODE_ENV")!=="production",debug:y.readRuntimeEnv("NODE_ENV")==="development"}}class v{id="aligo";name="Aligo Smart SMS";supportedTypes=["ALIMTALK","FRIENDTALK","SMS","LMS","MMS"];transportCapabilities={abortSignal:"supported",injectableFetch:"supported"};config;smsHost;alimtalkHost;getOnboardingSpec(){let e=F(this.id);if(!e)throw Error(`Onboarding spec missing for provider: ${this.id}`);return e}constructor(e){if(!e||typeof e!=="object")throw Error("AligoProvider requires a config object");if(!e.apiKey||e.apiKey.length===0)throw Error("AligoProvider requires `apiKey`");if(!e.userId||e.userId.length===0)throw Error("AligoProvider requires `userId`");this.config=e,this.smsHost=e.smsBaseUrl||"https://apis.aligo.in",this.alimtalkHost=e.alimtalkBaseUrl||"https://kakaoapi.aligo.in"}getRuntimeContext(e){return{providerId:this.id,config:this.config,smsHost:this.smsHost,alimtalkHost:this.alimtalkHost,requestContext:e}}async healthCheck(){let e=Date.now(),r=[];try{if(!this.config.apiKey)r.push("Missing apiKey");if(!this.config.userId)r.push("Missing userId");if(!this.config.sender)r.push("Missing sender (default from)");try{new URL(this.smsHost)}catch{r.push("Invalid smsBaseUrl")}try{new URL(this.alimtalkHost)}catch{r.push("Invalid alimtalkBaseUrl")}return{healthy:r.length===0,issues:r,latencyMs:Date.now()-e,data:{provider:this.id,smsBaseUrl:this.smsHost,alimtalkBaseUrl:this.alimtalkHost}}}catch(t){return r.push(t instanceof Error?t.message:String(t)),{healthy:!1,issues:r,latencyMs:Date.now()-e}}}async send(e,r){let t=e.messageId||crypto.randomUUID(),n={...e,messageId:t};return J(this.getRuntimeContext(r),n)}async listKakaoChannels(e){return H(this.getRuntimeContext(),e)}async listKakaoChannelCategories(){return Y(this.getRuntimeContext())}async requestKakaoChannelAuth(e){return B(this.getRuntimeContext(),e)}async addKakaoChannel(e){return G(this.getRuntimeContext(),e)}}var C=(e)=>new v(e),_=()=>{let e=ge();if(!e.apiKey||!e.userId)throw Error("ALIGO_API_KEY and ALIGO_USER_ID are required");return new v(e)};class P{static create(e){return new v(e)}static createDefault(){return _()}} //# debugId=A0FA87B2DB819D8364756E2164756E21 //# sourceMappingURL=send.js.map