serverless-aws-lambda
Version:
AWS Application Load Balancer and API Gateway - Lambda dev tool for Serverless. Allows Express synthax in handlers. Supports packaging, local invoking and offline ALB, APG, S3, SNS, SQS, DynamoDB Stream server mocking.
39 lines (38 loc) • 11.3 kB
JavaScript
var D=Object.defineProperty;var L=(s,e,t)=>e in s?D(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var C=(s,e,t)=>L(s,typeof e!="symbol"?e+"":e,t);var v=(s,e,t)=>new Promise((n,a)=>{var l=f=>{try{u(t.next(f))}catch(c){a(c)}},i=f=>{try{u(t.throw(f))}catch(c){a(c)}},u=f=>f.done?n(f.value):Promise.resolve(f.value).then(l,i);u((t=t.apply(s,e)).next())});import{randomUUID as w}from"crypto";import{randomUUID as N}from"crypto";var x=(s,e,t)=>{switch(s){case"=":return e==t;case">":return e>t;case"<":return e<t;case">=":return e>=t;case"<=":return e>=t;default:return!1}},B={exists:(s,e,t)=>{if(t===!0)return e in s;if(t===!1)return!(e in s);throw new Error("stream filter 'exists' value must be 'true' or 'false'")},prefix:(s,e,t)=>{if(typeof t!="string")throw new Error("SQS filter 'prefix' value must be typeof 'string'");let n=typeof s[e]=="string"?s[e]:void 0;return n?n.startsWith(t):!1},numeric:(s,e,t)=>{if(!Array.isArray(t)||![2,4].includes(t.length))throw new Error("SQS filter 'numeric' value must be an array with 2 or 4 items");if(!(e in s))return!1;let n=[],[a,l]=t;if(n.push(x(a,s[e],l)),t.length==4){let[,,i,u]=t;n.push(x(i,s[e],u))}return n.every(i=>i===!0)},"anything-but":(s,e,t)=>{if(!Array.isArray(t)||!t.every(a=>typeof a=="string"))throw new Error("SQS filter 'anything-but' value must be an array of string");let n=typeof s[e]=="string"?s[e]:void 0;return n?!t.includes(n):!1}},H=(s,e,t)=>{let n=typeof t;if(n=="string"||n===null)return s[e]==t;if(n=="object"&&!Array.isArray(t)){let a=[];for(let[l,i]of Object.entries(t))l in B&&a.push(B[l](s,e,i));return a.every(l=>l===!0)}return!1},$=(s,e)=>{let t=[];for(let[n,a]of Object.entries(s)){let l=[];Array.isArray(a)?l=a.map(i=>H(e,n,i)):e[n]&&(l=[$(a,e[n])]),t.push(l.some(i=>i===!0))}return t.every(n=>n===!0)};var m=class s extends Error{constructor({Code:t,Message:n,SenderFault:a}){super(n);C(this,"Code");C(this,"SenderFault",!0);this.Code=t,typeof a=="boolean"&&(this.SenderFault=a)}toXml(t){return s.genericErrorResponse({RequestId:t,Code:this.Code,Message:this.message,SenderFault:this.SenderFault})}static genericErrorResponse({RequestId:t,Code:n,Message:a,SenderFault:l}){return`<?xml version="1.0"?>
<ErrorResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
<Error>
<Type>${l?"Sender":"Server"}</Type>
<Code>${n!=null?n:"UnknownOperation"}</Code>
<Message>${a}</Message>
</Error>
<RequestId>${t}</RequestId>
</ErrorResponse>`}};var q=new Set(["Binary","Number","String"]),j=s=>{let e={},t={},n={},a=new Set([]);for(let l of s){let[i,u,...f]=l.split("=");if(i.startsWith("MessageAttributes")){let[c,r,o,d,g]=i.split(".");if(d=="Name")t[u]={Type:"",Value:""},n[o]=u;else if(d=="Value")if(g=="DataType")t[n[o]].Type=u;else{let M=n[o];if(a.has(M))throw new m({Code:"ParameterValueInvalid",Message:`Message attribute name '${M}' has multiple values.`});let p=[u,...f].join("="),h=t[M].Type;if(p){if(h=="Binary"&&g=="StringValue")throw new m({Code:"ParameterValueInvalid",Message:`The message attribute '${M}' with type 'Binary' must use field 'Binary'.`});if((h=="String"||h=="Number")&&g=="BinaryValue")throw new m({Code:"ParameterValueInvalid",Message:`The message attribute '${M}' with type '${h}' must use field 'String'.`})}t[M].Value=p,a.add(M)}}else e[i]=[u,...f].join("=")}return Object.keys(t).length&&(F(t),e.MessageAttributes=t),e},z=s=>{for(let e of s)if(s.filter(t=>t==e).length>1)throw new m({Code:"BatchEntryIdsNotDistinct",Message:"Two or more batch entries in the request have the same Id."})},F=s=>{for(let[e,t]of Object.entries(s)){let{Type:n,Value:a}=t;if(!q.has(n))throw new m({Code:"ParameterValueInvalid",Message:`The message attribute '${e}' has an invalid message attribute type, the set of supported type prefixes is Binary, Number, and String.`});if((n=="String"||n=="Number")&&!a)throw new m({Code:"ParameterValueInvalid",Message:`The message attribute '${e}' must contain non-empty message attribute value for message attribute type '${n}'.`});if(n=="Number"&&isNaN(a))throw new m({Code:"ParameterValueInvalid",Message:`Could not cast message attribute '${e}' value to number.`})}},V=s=>{var f;let e={},t=[],n=N(),a=[],l=[],i=new Map,u=new Set([]);for(let c of s){let[r,o]=c.split("=");if(r.startsWith("PublishBatchRequestEntries")){let[,,d,g,M,p,h,S]=r.split("."),y=i.get(d);if(y){if(g=="Message"||g=="MessageStructure"||g=="Subject"||g=="Id")y.value[g]=o;else if(g=="MessageAttributes"){let b=y.attributes[p];if(b)if(S=="DataType")y.value.MessageAttributes[b].Type=o;else{let I=`${d}-${b}`;if(u.has(I))throw new m({Code:"ParameterValueInvalid",Message:`Message attribute name '${b}' has multiple values.`});let[,...U]=c.split("="),E=U.join("="),A=y.value.MessageAttributes[b].Type;if(E){if(A=="Binary"&&S=="StringValue")throw new m({Code:"ParameterValueInvalid",Message:`The message attribute '${b}' with type 'Binary' must use field 'Binary'.`});if((A=="String"||A=="Number")&&S=="BinaryValue")throw new m({Code:"ParameterValueInvalid",Message:`The message attribute '${b}' with type '${A}' must use field 'String'.`})}y.value.MessageAttributes[b].Value=E,u.add(I)}else y.attributes[p]=o,y.value.MessageAttributes?y.value.MessageAttributes[o]={}:y.value.MessageAttributes={[o]:{}}}}else{let b={attributes:{},value:{}};g=="Message"||g=="MessageStructure"||g=="Subject"||g=="Id"?b.value[g]=o:g=="MessageAttributes"&&(b.attributes[p]=o,b.value.MessageAttributes={[o]:{}}),i.set(d,b)}}else e[r]=o}for(let c of i.values()){let r={Type:"Notification",MessageId:N(),TopicArn:e.TopicArn,Subject:(f=c.value.Subject)!=null?f:null,Timestamp:new Date().toISOString(),SignatureVersion:"1",Signature:"fake",SigningCertUrl:"fake",UnsubscribeUrl:"fake",MessageStructure:c.value.MessageStructure};"Message"in c.value&&(r.Message=c.value.Message),c.value.MessageAttributes&&(r.MessageAttributes=c.value.MessageAttributes);let o={EventSource:"aws:sns",EventVersion:"1.0",EventSubscriptionArn:`${e.TopicArn}:${n}`,Sns:r};try{k(r),delete r.MessageStructure,a.push(o)}catch(d){d instanceof m&&l.push({Id:c.value.Id,Code:d.Code,SenderFault:d.SenderFault,Message:d.message})}finally{t.push(c.value.Id)}}return z(t),a.forEach(c=>{c.Sns.MessageAttributes&&F(c.Sns.MessageAttributes)}),{Records:a,Ids:t,Failed:l}},k=s=>{if(!("Message"in s))throw new m({Code:"ValidationError",Message:"1 validation error detected: Value null at 'message' failed to satisfy constraint: Member must not be null"});if(s.Message=="")throw new m({Code:"InvalidParameter",Message:"Invalid parameter: Empty message"});if(s.MessageStructure=="json"){try{s.Message=JSON.parse(s.Message)}catch(t){throw new m({Code:"InvalidParameter",Message:"Invalid parameter: Message Structure - Failed to parse JSON"})}let e=typeof s.Message.default;if(e=="number"||e=="boolean"||s.Message.default===null)s.Message=String(s.Message.default);else if(e=="string")s.Message=s.Message.default;else throw new m({Code:"InvalidParameter",Message:"Invalid parameter: Message Structure - No default entry in JSON message body"})}},P=(s,e)=>{var t;return k(s),{Records:[{EventSource:"aws:sns",EventVersion:"1.0",EventSubscriptionArn:s.TopicArn,Sns:{Type:"Notification",MessageId:e,TopicArn:s.TopicArn,Subject:(t=s.Subject)!=null?t:null,Message:s.Message,Timestamp:new Date().toISOString(),SignatureVersion:"1",Signature:"fake",SigningCertUrl:"fake",UnsubscribeUrl:"fake",MessageAttributes:s.MessageAttributes}}]}},R=(s,e)=>{let t=s.TopicArn.split(":"),n=t[t.length-1],a=[];return e.forEach(l=>{let i=l.sns.find(u=>{if(!u||u.name!==n)return!1;if(!u.filter)return!0;let f={};if(u.filterScope=="MessageAttributes"){if(!s.MessageAttributes)return!1;for(let[c,r]of Object.entries(s.MessageAttributes))f[c]=r.Value}else if(u.filterScope=="MessageBody"){if(s.MessageStructure!="json"||!s.Message)return!1;try{f=JSON.parse(s.Message)}catch(c){}}return $(u.filter,f)});i&&a.push({handler:l,event:i})}),a},T=(s,e)=>`<PublishResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
<PublishResult>
<MessageId>${s}</MessageId>
</PublishResult>
<ResponseMetadata>
<RequestId>${e}</RequestId>
</ResponseMetadata>
</PublishResponse>`,O=(s,e,t)=>{let n="<Successful/>",a="<Failed/>";return e.length&&(n=`<Successful>
${e.map(i=>`<member>
<MessageId>${i.MessageId}</MessageId>
<Id>${i.Id}</Id>
</member>`).join(`
`)}
</Successful>`),t.length&&(a=`<Failed>
${t.map(i=>`<member>
<Code>${i.Code}</Code>
<SenderFault>${i.SenderFault}</SenderFault>
<Id>${i.Id}</Id>
<Message>${i.Message}</Message>
</member>`).join(`
`)}
</Failed>`),`<PublishBatchResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
<PublishBatchResult>
${a}
${n}
</PublishBatchResult>
<ResponseMetadata>
<RequestId>${s}</RequestId>
</ResponseMetadata>
</PublishBatchResponse>`};var J=()=>({name:"sns-plugin",offline:{request:[{method:"POST",filter:"/@sns/parsed",callback:function(s,e){return v(this,null,function*(){var c;let t=Buffer.alloc(0),n=w(),a=(c=s.headers["amz-sdk-invocation-id"])!=null?c:w();s.on("data",r=>{t+=r});let l=yield new Promise(r=>{s.on("end",()=>v(this,null,function*(){r(JSON.parse(t.toString()))}))}),i=R(l,this.lambdas),u=[];if(i.length){let r=P(l,n);i.forEach(o=>{u.find(d=>d.handler.name==o.handler.name)||u.push(o)});for(let{handler:o,event:d}of u){let g=`SNS: ${d.name}`;d.displayName&&(g+=` | ${d.displayName}`),console.log(`\x1B[35m${g}\x1B[0m`);try{yield o.invoke(r,{kind:"sns",event:d})}catch(M){console.log(M)}}}e.statusCode=200,e.setHeader("Content-Type","text/xml");let f=T(n,a);e.end(f)})}},{method:"POST",filter:"/@sns",callback:function(s,e){return v(this,null,function*(){var f,c;let t=Buffer.alloc(0),n=w(),a=(f=s.headers["amz-sdk-invocation-id"])!=null?f:w(),l=r=>{var o,d;e.statusCode=400,r instanceof m?e.end(r.toXml(a)):e.end(m.genericErrorResponse({RequestId:a,Message:(d=(o=r.toString)==null?void 0:o.call(r))!=null?d:"Unknown error"}))};e.setHeader("Content-Type","text/xml"),e.setHeader("x-amzn-requestid",w()),s.on("data",r=>{t+=r});let i=yield new Promise(r=>{s.on("end",()=>v(this,null,function*(){var o;r((o=decodeURIComponent(t.toString()))==null?void 0:o.split("&"))}))}),u=(c=i.find(r=>r.startsWith("Action=")))==null?void 0:c.split("=")[1];if(u)if(u=="Publish")try{let r=j(i),o=R(r,this.lambdas),d=[],g=P(r,n);if(o.length){o.forEach(p=>{d.find(h=>h.handler.name==p.handler.name)||d.push(p)});for(let{handler:p,event:h}of d){let S=`SNS: ${h.name}`;h.displayName&&(S+=` | ${h.displayName}`),console.log(`\x1B[35m${S}\x1B[0m`);try{yield p.invoke(g,{kind:"sns",event:h})}catch(y){console.log(y)}}}e.statusCode=200;let M=T(n,a);e.end(M)}catch(r){l(r)}else if(u=="PublishBatch")try{let r=V(i),o=[],d=r.Failed,g=[];r.Records.forEach((p,h)=>{let S=r.Ids[h];o.push({Id:S,MessageId:p.Sns.MessageId});let y=R(p.Sns,this.lambdas);y.length&&y.forEach(b=>{g.find(I=>I.handler.name==b.handler.name)||g.push(b)})}),e.statusCode=200;let M=O(a,o,d);e.end(M);for(let{handler:p,event:h}of g)try{yield p.invoke({Records:r.Records},{kind:"sns",event:h})}catch(S){console.log(S)}}catch(r){l(r)}else e.statusCode=400,e.end(m.genericErrorResponse({RequestId:a,Message:`Action "${u}" is currently not supported`}))})}}]}}),ie=J;export{ie as default,J as snsPlugin};