exlo 0.0.1

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.
Files changed (151) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.mjs +11 -0
  3. package/dist/config.d.ts +35 -0
  4. package/dist/defineConfig.d.ts +125 -0
  5. package/dist/defineConfig.mjs +1 -0
  6. package/dist/lib/esbuild/buildOptimizer.d.ts +9 -0
  7. package/dist/lib/esbuild/knownCjs.d.ts +1 -0
  8. package/dist/lib/esbuild/mergeEsbuildConfig.d.ts +2 -0
  9. package/dist/lib/esbuild/parseCustomEsbuild.d.ts +2 -0
  10. package/dist/lib/parseEvents/ddbStream.d.ts +17 -0
  11. package/dist/lib/parseEvents/endpoints.d.ts +29 -0
  12. package/dist/lib/parseEvents/funcUrl.d.ts +2 -0
  13. package/dist/lib/parseEvents/index.d.ts +16 -0
  14. package/dist/lib/parseEvents/sqs.d.ts +11 -0
  15. package/dist/lib/runtime/bufferedStreamResponse.d.ts +24 -0
  16. package/dist/lib/runtime/callDestinations.d.ts +12 -0
  17. package/dist/lib/runtime/eventSourceMapping/base.d.ts +66 -0
  18. package/dist/lib/runtime/eventSourceMapping/base.mjs +1 -0
  19. package/dist/lib/runtime/eventSourceMapping/errors/eventSourceMappingError.d.ts +5 -0
  20. package/dist/lib/runtime/eventSourceMapping/esmBatch.d.ts +15 -0
  21. package/dist/lib/runtime/eventSourceMapping/filter/compileFilterPolicy.d.ts +12 -0
  22. package/dist/lib/runtime/eventSourceMapping/filter/compileFilterPolicy.test.d.ts +1 -0
  23. package/dist/lib/runtime/eventSourceMapping/filter/compileWildcard.d.ts +1 -0
  24. package/dist/lib/runtime/eventSourceMapping/filter/compileWildcard.test.d.ts +1 -0
  25. package/dist/lib/runtime/eventSourceMapping/filter/expandDotPathsWithStrictConflicts.d.ts +1 -0
  26. package/dist/lib/runtime/eventSourceMapping/filter/expandDotPathsWithStrictConflicts.test.d.ts +1 -0
  27. package/dist/lib/runtime/eventSourceMapping/filter/matchesFilterPolicy.d.ts +2 -0
  28. package/dist/lib/runtime/eventSourceMapping/filter/matchesFilterPolicy.test.d.ts +1 -0
  29. package/dist/lib/runtime/eventSourceMapping/sqs.d.ts +19 -0
  30. package/dist/lib/runtime/eventSourceMapping/utils.d.ts +6 -0
  31. package/dist/lib/runtime/rapidApi.d.ts +97 -0
  32. package/dist/lib/runtime/runners/index.d.ts +25 -0
  33. package/dist/lib/runtime/runners/node/awslambda.d.ts +11 -0
  34. package/dist/lib/runtime/runners/node/index.d.ts +1 -0
  35. package/dist/lib/runtime/runners/node/index.js +19 -0
  36. package/dist/lib/runtime/runners/node/runner.d.ts +34 -0
  37. package/dist/lib/runtime/runners/node/streamResponse.d.ts +90 -0
  38. package/dist/lib/runtime/runners/node/utils.d.ts +39 -0
  39. package/dist/lib/runtime/runners/python/runner.d.ts +48 -0
  40. package/dist/lib/runtime/runners/ruby/runner.d.ts +43 -0
  41. package/dist/lib/server/daemon.d.ts +27 -0
  42. package/dist/lib/server/handlers.d.ts +13 -0
  43. package/dist/lib/services/index.d.ts +10 -0
  44. package/dist/lib/utils/amazonifyHeaders.d.ts +3 -0
  45. package/dist/lib/utils/colorize.d.ts +12 -0
  46. package/dist/lib/utils/getPackageInstalledDir.d.ts +1 -0
  47. package/dist/lib/utils/readDefineConfig.d.ts +6 -0
  48. package/dist/main.d.ts +80 -0
  49. package/dist/plugins/lambda/events/alb.d.ts +44 -0
  50. package/dist/plugins/lambda/events/apg.d.ts +111 -0
  51. package/dist/plugins/lambda/events/common.d.ts +114 -0
  52. package/dist/plugins/lambda/functionUrlInvoke.d.ts +3 -0
  53. package/dist/plugins/lambda/htmlStatusMsg.d.ts +4 -0
  54. package/dist/plugins/lambda/index.d.ts +3 -0
  55. package/dist/plugins/lambda/invokeRequests.d.ts +3 -0
  56. package/dist/plugins/lambda/lambdaApi.d.ts +6 -0
  57. package/dist/plugins/lambda/responseStreamingInvoke.d.ts +3 -0
  58. package/dist/plugins/lambda/streamEncoder.d.ts +19 -0
  59. package/dist/plugins/lambda/utils.d.ts +29 -0
  60. package/dist/plugins/restApi/compileAjvSchema.d.ts +1 -0
  61. package/dist/plugins/restApi/errors.d.ts +32 -0
  62. package/dist/plugins/restApi/findRequestResource.d.ts +9 -0
  63. package/dist/plugins/restApi/findRequestResource.test.d.ts +1 -0
  64. package/dist/plugins/restApi/index.d.ts +8 -0
  65. package/dist/plugins/restApi/index.mjs +1 -0
  66. package/dist/plugins/restApi/resourcesFromOpenApi.d.ts +4 -0
  67. package/dist/plugins/restApi/restApiServer.d.ts +265 -0
  68. package/dist/plugins/restApi/restApiServer.test.d.ts +1 -0
  69. package/dist/plugins/restApi/utils.d.ts +9 -0
  70. package/dist/plugins/s3/actions/AbortMultipartUploadAction.d.ts +10 -0
  71. package/dist/plugins/s3/actions/CompleteMultipartUploadAction.d.ts +15 -0
  72. package/dist/plugins/s3/actions/CopyObjectAction.d.ts +24 -0
  73. package/dist/plugins/s3/actions/CreateBucketAction.d.ts +8 -0
  74. package/dist/plugins/s3/actions/CreateMultipartUploadAction.d.ts +13 -0
  75. package/dist/plugins/s3/actions/DeleteBucketAction.d.ts +8 -0
  76. package/dist/plugins/s3/actions/DeleteBucketPolicyAction.d.ts +8 -0
  77. package/dist/plugins/s3/actions/DeleteBucketTaggingAction.d.ts +8 -0
  78. package/dist/plugins/s3/actions/DeleteObjectAction.d.ts +10 -0
  79. package/dist/plugins/s3/actions/DeleteObjectTaggingAction.d.ts +9 -0
  80. package/dist/plugins/s3/actions/DeleteObjectsAction.d.ts +8 -0
  81. package/dist/plugins/s3/actions/GetBucketAclAction.d.ts +8 -0
  82. package/dist/plugins/s3/actions/GetBucketPolicy.d.ts +8 -0
  83. package/dist/plugins/s3/actions/GetBucketTaggingAction.d.ts +8 -0
  84. package/dist/plugins/s3/actions/GetObjectAclAction.d.ts +8 -0
  85. package/dist/plugins/s3/actions/GetObjectAction.d.ts +30 -0
  86. package/dist/plugins/s3/actions/GetObjectTaggingAction.d.ts +10 -0
  87. package/dist/plugins/s3/actions/HeadBucketAction.d.ts +8 -0
  88. package/dist/plugins/s3/actions/HeadObjectAction.d.ts +18 -0
  89. package/dist/plugins/s3/actions/ListBucketsAction.d.ts +15 -0
  90. package/dist/plugins/s3/actions/ListMultipartUploadsAction.d.ts +19 -0
  91. package/dist/plugins/s3/actions/ListObjectsAction.d.ts +31 -0
  92. package/dist/plugins/s3/actions/ListPartsAction.d.ts +14 -0
  93. package/dist/plugins/s3/actions/PutBucketAclAction.d.ts +11 -0
  94. package/dist/plugins/s3/actions/PutBucketCorsAction.d.ts +8 -0
  95. package/dist/plugins/s3/actions/PutBucketPolicyAction.d.ts +9 -0
  96. package/dist/plugins/s3/actions/PutBucketTaggingAction.d.ts +8 -0
  97. package/dist/plugins/s3/actions/PutObjectAclAction.d.ts +8 -0
  98. package/dist/plugins/s3/actions/PutObjectAction.d.ts +22 -0
  99. package/dist/plugins/s3/actions/PutObjectTaggingAction.d.ts +9 -0
  100. package/dist/plugins/s3/actions/UnknownAction.d.ts +7 -0
  101. package/dist/plugins/s3/actions/UploadPartAction.d.ts +12 -0
  102. package/dist/plugins/s3/actions/localAction.d.ts +92 -0
  103. package/dist/plugins/s3/calulcateETag.d.ts +1 -0
  104. package/dist/plugins/s3/commons/constants.d.ts +6 -0
  105. package/dist/plugins/s3/commons/utils.d.ts +3 -0
  106. package/dist/plugins/s3/errors/notFound.d.ts +8 -0
  107. package/dist/plugins/s3/errors/s3Error.d.ts +65 -0
  108. package/dist/plugins/s3/getLocalStoragePath.d.ts +1 -0
  109. package/dist/plugins/s3/index.d.ts +32 -0
  110. package/dist/plugins/s3/index.mjs +97 -0
  111. package/dist/plugins/s3/lib/createS3Server.d.ts +38 -0
  112. package/dist/plugins/s3/parsers/parseDeleteRequest.d.ts +10 -0
  113. package/dist/plugins/s3/parsers/parseGetRequest.d.ts +14 -0
  114. package/dist/plugins/s3/parsers/parseHeadRequest.d.ts +5 -0
  115. package/dist/plugins/s3/parsers/parsePostRequest.d.ts +7 -0
  116. package/dist/plugins/s3/parsers/parsePutRequest.d.ts +14 -0
  117. package/dist/plugins/s3/triggerEvent.d.ts +12 -0
  118. package/dist/plugins/sns/errors.d.ts +26 -0
  119. package/dist/plugins/sns/filter.d.ts +1 -0
  120. package/dist/plugins/sns/filter.test.d.ts +1 -0
  121. package/dist/plugins/sns/index.d.ts +23 -0
  122. package/dist/plugins/sns/index.mjs +106 -0
  123. package/dist/plugins/sns/parsers/parseCreateTopic.d.ts +2 -0
  124. package/dist/plugins/sns/parsers/parseMessage.d.ts +18 -0
  125. package/dist/plugins/sns/parsers/parsePublishMessage.d.ts +6 -0
  126. package/dist/plugins/sns/parsers/parsePublishMessageBatch.d.ts +9 -0
  127. package/dist/plugins/sns/parsers/parseSubscribe.d.ts +17 -0
  128. package/dist/plugins/sns/parsers/parseSubscriptionArn.d.ts +6 -0
  129. package/dist/plugins/sns/parsers/parseTopicArn.d.ts +4 -0
  130. package/dist/plugins/sns/server.d.ts +36 -0
  131. package/dist/plugins/sns/server.test.d.ts +1 -0
  132. package/dist/plugins/sns/subscriber/index.d.ts +61 -0
  133. package/dist/plugins/sns/subscriber/validateConfig.d.ts +0 -0
  134. package/dist/plugins/sns/topic.d.ts +91 -0
  135. package/dist/plugins/sns/utils.d.ts +20 -0
  136. package/dist/plugins/sns/validateFilterPolicy.d.ts +19 -0
  137. package/dist/plugins/sns/validateFilterPolicy.test.d.ts +1 -0
  138. package/dist/plugins/sqs/index.d.ts +16 -0
  139. package/dist/plugins/sqs/index.mjs +1 -0
  140. package/dist/plugins/sqs/types.d.ts +11 -0
  141. package/dist/plugins/sqs/utils.d.ts +7 -0
  142. package/dist/plugins/vitest/coverage.d.ts +6 -0
  143. package/dist/plugins/vitest/index.d.ts +29 -0
  144. package/dist/plugins/vitest/index.mjs +1 -0
  145. package/dist/standalone.d.ts +17 -0
  146. package/dist/standalone.js +13 -0
  147. package/dist/standalone.mjs +13 -0
  148. package/dist/standalone_types.d.ts +190 -0
  149. package/package.json +119 -0
  150. package/src/lib/runtime/runners/python/index.py +105 -0
  151. package/src/lib/runtime/runners/ruby/index.rb +67 -0
@@ -0,0 +1,106 @@
1
+ import{SNS as Te}from"@aws-sdk/client-sns";var a=class s extends Error{Code;SenderFault=!0;statusCode=400;constructor({Code:e,Message:t,SenderFault:i,statusCode:r}){super(t),this.Code=e,typeof i=="boolean"&&(this.SenderFault=i),r&&(this.statusCode=r)}toXml(e){return s.genericErrorResponse({RequestId:e,Code:this.Code,Message:this.message,SenderFault:this.SenderFault})}static genericErrorResponse({RequestId:e,Code:t,Message:i,SenderFault:r}){return`<?xml version="1.0"?>
2
+ <ErrorResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
3
+ <Error>
4
+ <Type>${r?"Sender":"Server"}</Type>
5
+ <Code>${t??"UnknownOperation"}</Code>
6
+ <Message>${i}</Message>
7
+ </Error>
8
+ <RequestId>${e}</RequestId>
9
+ </ErrorResponse>`}},u=class extends a{constructor(e){super({Code:"InvalidParameter",SenderFault:!0,Message:e,statusCode:400})}},M=class extends a{constructor(e){super({Code:"ValidationError",SenderFault:!0,Message:e,statusCode:400})}};import{randomUUID as C}from"node:crypto";import{createServer as Ae}from"node:http";import{isDeepStrictEqual as ve}from"node:util";import{decode as Me}from"aws-query-decoder";import{EventSourceMapping as We}from"exlo/internal/esm";import{EventSourceMapping as $e}from"exlo/internal/esm";var m=s=>Object.prototype.toString.call(s)=="[object Object]";function X(s){if(s.Attributes==null)return;if(s.Attributes.member||!Array.isArray(s.Attributes.entry))throw new u("Attributes must provide entry list");let e={};for(let t=0;t<s.Attributes.entry.length;t++){let i=s.Attributes.entry[t];if(!m(i)||typeof i.key!="string"||typeof i.value!="string")throw new u("Attribute must provide key and value, both string.");let{key:r,value:n}=i,o=n;if(["FifoTopic","ContentBasedDeduplication"].includes(r))if(n=="true")o=!0;else if(n=="false")o=!1;else throw new u(`${r} value must be true or false.`);else if(["DeliveryPolicy","Policy","ArchivePolicy"].includes(r))try{let l=JSON.parse(n);if(!m(l))throw new Error("Invalid policy")}catch{throw new u(`Invalid ${r} value. Must be valid JSON policy string.`)}e[r]=o}return e}function Y(s){if(s.Tags==null)return;if(s.Tags.member&&!Array.isArray(s.Tags.member))throw new u("Tags must provide member list");let e=[];for(let t=0;t<s.Tags.member.length;t++){let i=s.Tags.member[t];if(!m(i)||typeof i.Key!="string"||typeof i.Value!="string")throw new u("Tag must provide Key and Value, both string.");let{Key:r,Value:n}=i;e.push({Key:r,Value:n})}return e}function O(s){if(!m(s))throw new u("Invalid request body.");if(typeof s.Name!="string")throw new u("Name must be a string");return{Name:s.Name,Attributes:X(s),Tags:Y(s)}}function Z(s){return["String","Number","Binary"].includes(s)?!0:!s.endsWith(".")&&(s.startsWith("String.")||s.startsWith("Number.")||s.startsWith("Binary."))}var ee="abcdefghijklmnopqrstuvwxyz0123456789_-.";function te(s){let e=s.split("").find(t=>ee.indexOf(t)==-1);if(e)return`#x${e.charCodeAt(0).toString(16)}`}var T=s=>{let e=null,t,i,r,n,o,l,p={},f,g,b,h=0;if(!("Message"in s))throw new a({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 a({Code:"InvalidParameter",Message:"Invalid parameter: Empty message"});if(t=s.Message,h=Buffer.from(t,"utf-8").byteLength,"Subject"in s){if(typeof s.Subject!="string"||!s.Subject.trim())throw new a({Code:"InvalidParameter",Message:"Invalid parameter: Subject"});e=s.Subject}if("MessageGroupId"in s){if(typeof s.MessageGroupId!="string"||!s.MessageGroupId||s.MessageGroupId.length>128)throw new a({Code:"InvalidParameter",Message:"Invalid parameter: The MessageGroupId parameter can only include alphanumeric and punctuation characters. 1 to 128 in length"});f=s.MessageGroupId}if("MessageDeduplicationId"in s){if(typeof s.MessageDeduplicationId!="string"||!s.MessageDeduplicationId||s.MessageDeduplicationId.length>128)throw new a({Code:"InvalidParameter",Message:"Invalid parameter: The MessageDeduplicationId parameter can only include alphanumeric and punctuation characters. 1 to 128 in length"});g=s.MessageDeduplicationId}if(typeof s.MessageStructure=="string"&&s.MessageStructure.toLowerCase()=="json"){b="json";let c;try{c=JSON.parse(t)}catch{throw new a({Code:"InvalidParameter",Message:"Invalid parameter: Message Structure - Failed to parse JSON"})}let y=typeof c.default;if(y=="number"||y=="boolean"||c.default===null)i=String(c.default);else if(y=="string")i=c.default;else throw new a({Code:"InvalidParameter",Message:"Invalid parameter: Message Structure - No default entry in JSON message body"});typeof c.sqs=="string"&&(r=c.sqs),typeof c.http=="string"&&(n=c.http),typeof c.https=="string"&&(o=c.https),typeof c.lambda=="string"&&(l=c.lambda)}if("MessageAttributes"in s){if(!Array.isArray(s.MessageAttributes.entry))throw new a({Code:"MalformedInput",Message:"Malformed MessageAttributes"});for(let c of s.MessageAttributes.entry){if(!c?.Name||typeof c?.Name!="string")throw new a({Code:"MalformedInput",Message:"Malformed MessageAttributes"});let y=c.Name.toLowerCase();if(y.startsWith("aws.")||y.startsWith("amazon."))throw new a({Code:"ParameterValueInvalid",Message:"Message attribute names starting with 'AWS.' or 'Amazon.' are reserved for use by Amazon."});let w=te(y);if(w)throw new a({Code:"ParameterValueInvalid",Message:`Invalid non-alphanumeric character '${w}' was found in the message attribute name. Can only include alphanumeric characters, hyphens, underscores, or dots.`});if(c.Name.length>256)throw new a({Code:"ParameterValueInvalid",Message:"Length of message attribute name must be less than 256 bytes."});if(c.Name.startsWith("."))throw new a({Code:"ParameterValueInvalid",Message:"Invalid message attribute name starting with character '.' was found."});if(c.Name.endsWith("."))throw new a({Code:"ParameterValueInvalid",Message:"Invalid message attribute name ending with character '.' was found."});if(c.Name.includes(".."))throw new a({Code:"ParameterValueInvalid",Message:"Message attribute name can not have successive '.' character."});if(!m(c.Value))throw new a({Code:"MalformedInput",Message:"Malformed MessageAttributes"});if(!c.Value.DataType)throw new a({Code:"ValidationError",Message:`1 validation error detected: Value null at 'messageAttributes.${c.Name}.member.dataType' failed to satisfy constraint: Member must not be null`});if(typeof c.Value.DataType!="string")throw new a({Code:"ValidationError",Message:`1 validation error detected: Value null at 'messageAttributes.${c.Name}.member.dataType' failed to satisfy constraint: Member must be string`});if(!Z(c.Value.DataType))throw new a({Code:"ParameterValueInvalid",Message:`The message attribute '${c.Name}' has an invalid message attribute type, the set of supported type prefixes is Binary, Number, and String.`});if(h+=Buffer.from(c.Value.DataType,"utf-8").byteLength,Object.keys(c.Value).filter(v=>["DataType","StringValue","BinaryValue"].includes(v)).length>2)throw new a({Code:"ParameterValueInvalid",Message:`Message attribute name '${c.Name}' has multiple values.`});if(c.Value.DataType.startsWith("Binary")){if(!("BinaryValue"in c.Value))throw new a({Code:"ParameterValueInvalid",Message:`The message attribute '${c.Name}' with type '${c.Value.DataType}' must use field 'Binary'.`});if(!c.Value.BinaryValue)throw new a({Code:"ParameterValueInvalid",Message:`The message attribute '${c.Name}' must contain non-empty message attribute value for message attribute type 'Binary'.`});let v=!1;try{let D=Buffer.from(c.Value.BinaryValue,"base64");v=D.toString("base64")==c.Value.BinaryValue,h+=D.byteLength}catch{}if(!v)throw new a({Code:"ParameterValueInvalid",Message:`The message attribute '${c.Name}' must be base64 encoded string.`})}else{if(!("StringValue"in c.Value))throw new a({Code:"ParameterValueInvalid",Message:`The message attribute '${c.Name}' with type '${c.Value.DataType}' must use field 'String'.`});if(!c.Value.StringValue)throw new a({Code:"ParameterValueInvalid",Message:`The message attribute '${c.Name}' must contain non-empty message attribute value for message attribute type '${c.Value.DataType}'.`});if(c.Value.DataType.startsWith("Number")&&isNaN(c.Value.StringValue))throw new a({Code:"ParameterValueInvalid",Message:`Could not cast message attribute '${c.Name}' value to number.`});h+=Buffer.from(c.Value.StringValue,"utf-8").byteLength}h+=Buffer.from(c.Name,"utf-8").byteLength,p[c.Name]={Type:c.Value.DataType,Value:c.Value.StringValue??c.Value.BinaryValue}}}return{subject:e,message:t,messageSize:h,messageStructure:b,defaultMessage:i,sqsMessage:r,httpMessage:n,httpsMessage:o,lambdaMessage:l,messageAttributes:p,messageGroupId:f,messageDeduplicationId:g}};function S(s){if(!s.TopicArn)throw new u("Invalid parameter: TopicArn or TargetArn Reason: no value for required parameter");let e=s.TopicArn;if(e=s.TopicArn,typeof e!="string")throw new u("Invalid parameter: TopicArn Reason: An ARN must be a string");if(!(e.startsWith("arn:aws:sns:")||e.startsWith("arn:aws-cn:sns:")||e.startsWith("arn:aws-us-gov:sns:")))throw new u("Invalid parameter: TopicArn");let t=e.split(":");if(t.length<6)throw new u(`Invalid parameter: TopicArn Reason: An ARN must have at least 6 elements, not ${t.length}`);if(t.length>6)throw new u("Invalid parameter: Topic Name");let i=t[5];return{topicArn:e,topicName:i}}var L=s=>{let{topicArn:e,topicName:t}=S(s);return{topicName:t,topicArn:e,...T(s)}};var U=s=>{let{topicArn:e,topicName:t}=S(s),i=s.PublishBatchRequestEntries?.member;if(!Array.isArray(i))throw new a({Code:"ValidationError",Message:"1 validation error detected: Value null at 'publishBatchRequestEntries' failed to satisfy constraint: Member must not be null"});if(!i.length)throw new a({Code:"EmptyBatchRequest",Message:"The batch request doesn't contain any entries."});if(i.length>10)throw new a({Code:"TooManyEntriesInBatchRequest",Message:"The batch request contains more entries than permissible."});let r=[];for(let n=0;n<i.length;n++){let o=i[n];if(!m(o))throw new a({Code:"ValidationError",Message:"Validation error detected: Member at 'publishBatchRequestEntries' failed to satisfy constraint: Member must be object"});if(!("Id"in o))throw new a({Code:"ValidationError",Message:`Validation errors detected: Value null at 'publishBatchRequestEntries.${n+1}.member.id' failed to satisfy constraint: Member must not be null.`});let l=o.Id;if(typeof l!="string")throw new a({Code:"ValidationError",Message:`Validation errors detected: Value at 'publishBatchRequestEntries.${n+1}.member.id' failed to satisfy constraint: Member must be string.`});if(r.find(f=>f.Id==l))throw new a({Code:"BatchEntryIdsNotDistinct",Message:"Two or more batch entries in the request have the same Id."});let p=T(o);r.push({Id:l,message:p})}return{topicArn:e,topicName:t,parsedMessages:r}};var se=["DeliveryPolicy","FilterPolicy","FilterPolicyScope","RawMessageDelivery","RedrivePolicy","ReplayPolicy","SubscriptionRoleArn"];function ie(s){if(s.Attributes==null)return;if(s.Attributes.member||!Array.isArray(s.Attributes.entry))throw new u("Attributes must provide entry list");let e={};for(let t=0;t<s.Attributes.entry.length;t++){let i=s.Attributes.entry[t];if(!m(i)||typeof i.key!="string"||typeof i.value!="string")throw new u("Attribute must provide key and value, both string.");let{key:r,value:n}=i;if(!se.includes(r))throw new u(`Invalid parameter: Attributes Reason: Unknown attribute ${r}`);e[r]=n}return e}function j(s){let{topicArn:e,topicName:t}=S(s);if(!("Protocol"in s))throw new M("1 validation error detected: Value null at 'protocol' failed to satisfy constraint: Member must not be null");if(typeof s.Protocol!="string")throw new u(`Invalid parameter: Amazon SNS does not support this protocol string: ${s.Protocol}`);if(!["sqs","lambda","http","https","email","email-json","sms","application","firehose"].includes(s.Protocol.toLowerCase()))throw new u(`Invalid parameter: Amazon SNS does not support this protocol string: ${s.Protocol}`);let i=s.Protocol.toLowerCase();if(typeof s.Endpoint!="string")throw new u("Invalid parameter: Endpoint");let r=s.Endpoint,n=!1;if("ReturnSubscriptionArn"in s)if(s.ReturnSubscriptionArn=="true")n=!0;else if(s.ReturnSubscriptionArn=="false")n=!1;else throw new a({Code:"MalformedInput",SenderFault:!0,Message:"boolean must follow xsd1.1 definition",statusCode:400});return{TopicArn:e,topicName:t,Protocol:i,Endpoint:r,ReturnSubscriptionArn:n,Attributes:ie(s)}}var W=(s,e,t)=>{let i=`<PublishResult><MessageId>${s}</MessageId>`;return t&&(i+=`<SequenceNumber>${t}</SequenceNumber>`),i+="</PublishResult>",`<PublishResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
10
+ ${i}
11
+ <ResponseMetadata>
12
+ <RequestId>${e}</RequestId>
13
+ </ResponseMetadata>
14
+ </PublishResponse>`},Q=(s,e,t)=>{let i="<Successful/>",r="<Failed/>";if(e.length){i="<Successful>";for(let n of e){let o=`<member><MessageId>${n.MessageId}</MessageId><Id>${n.Id}</Id>`;n.SequenceNumber&&(o+=`<SequenceNumber>${n.SequenceNumber}</SequenceNumber>`),o+="</member>",i+=o}i+="</Successful>"}return t.length&&(r=`<Failed>
15
+ ${t.map(o=>`<member>
16
+ <Code>${o.Code}</Code>
17
+ <SenderFault>${o.SenderFault}</SenderFault>
18
+ <Id>${o.Id}</Id>
19
+ <Message>${o.Message}</Message>
20
+ </member>`).join(`
21
+ `)}
22
+ </Failed>`),`<PublishBatchResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
23
+ <PublishBatchResult>
24
+ ${r}
25
+ ${i}
26
+ </PublishBatchResult>
27
+ <ResponseMetadata>
28
+ <RequestId>${s}</RequestId>
29
+ </ResponseMetadata>
30
+ </PublishBatchResponse>`};function I(s){if(typeof s!="string")return null;let e=s.split(":");if(e.length<6||e[0]!=="arn")return null;let[t,i,r,n,o,...l]=e;if(!["aws","aws-cn","aws-us-gov"].includes(i))return null;let p=l.join(":"),f,g;return p.indexOf("/")!==-1?[f,g]=p.split("/"):p.indexOf(":")!==-1?[f,g]=p.split(":"):g=p,{partition:i,service:r,region:n,accountId:o,resourceType:f,resourceId:g}}function x(s){return s?s.service=="sqs"&&!s.resourceType:!1}function z(s){return s?s.service=="lambda"&&s.resourceType=="function":!1}function $(s){if(typeof s?.SubscriptionArn!="string")throw new u("Invalid parameter: SubscriptionArn Reason: An ARN must be a string");let e=s.SubscriptionArn.split(":");if(e<6)throw new u(`Invalid parameter: SubscriptionArn Reason: An ARN must have at least 6 elements, not ${e}`);let t=I(s.SubscriptionArn);if(t?.service!="sns"||!t.resourceType||!t.resourceId)throw new u("Invalid parameter: SubscriptionId");let i=s.SubscriptionArn;return{topicArn:i.slice(0,i.indexOf(`:${t.resourceId}`)),topicName:t.resourceType,subscriptionId:t.resourceId,SubscriptionArn:i}}import{randomUUID as k}from"node:crypto";import{setTimeout as ye}from"node:timers/promises";function ne(s,e){if(typeof e!="number")return!1;for(let t=0;t<s.length;t+=2){let i=s[t],r=s[t+1];if(!re(e,i,r))return!1}return!0}function re(s,e,t){switch(e){case"=":return s===t;case">":return s>t;case">=":return s>=t;case"<":return s<t;case"<=":return s<=t;default:return!1}}function G(s){return s.split(".").map(Number).reduce((e,t)=>(e<<8)+t,0)>>>0}function oe(s,e){let[t,i]=s.split("/"),r=G(e),n=G(t),o=~(2**(32-Number(i))-1)>>>0;return(r&o)===(n&o)}function R(s,e){if(s&&typeof s=="object"&&!Array.isArray(s)){if(s["anything-but"])return Array.isArray(s["anything-but"])?s["anything-but"].indexOf(e)==-1:!R(s["anything-but"],e);if(s["equals-ignore-case"])return typeof e=="string"&&e.toLowerCase()==s["equals-ignore-case"].toLowerCase();if(s.cidr)return typeof e!="string"?!1:oe(s.cidr,e);if(s.prefix)return typeof e=="string"&&e.startsWith(s.prefix);if(s.suffix)return typeof e=="string"&&e.endsWith(s.suffix);if(s.exists!==void 0)return s.exists?e!==void 0:e===void 0;if(s.numeric)return ne(s.numeric,e);if(s.$or)return s.$or.some(t=>A(t,e))}if(Array.isArray(s))if(Array.isArray(e)){if(!e.length){let t=s[0];if(m(t)&&"exists"in t)return!!t.exists}return s.some(t=>e.some(i=>R(t,i)))}else return s.some(t=>R(t,e));return e===s}function A(s,e){let t=[];for(let[i,r]of Object.entries(s)){if(Array.isArray(r)){if(i=="$or"){if(!r.some(o=>A(o,e)))return!1;t.push(!0)}else{if(!R(r,e?.[i]))return!1;t.push(!0)}continue}t.push(A(r,e?.[i]))}return!t.some(i=>!i)}var d=class extends u{constructor(e){super(`Invalid parameter: FilterPolicy: ${e}`),this.name="SnsFilterPolicyError"}},J=["<",">","<=",">="],ae=["exists","numeric","anything-but","equals-ignore-case","prefix","suffix","cidr"],ce=/^(?:(?:25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\/(?:3[0-2]|[12]?[0-9])$/;function ue(s){if(typeof s!="boolean")throw new d("exists match pattern must be either true or false")}function le(s){if(typeof s!="string")throw new d("equals-ignore-case match pattern must be a string")}function _(s){if(typeof s!="string")throw new d("prefix match pattern must be a string");if(!s)throw new d("Null prefix not allowed")}function pe(s){if(typeof s!="string")throw new d("suffix match pattern must be a string");if(!s)throw new d("Null suffix not allowed")}function de(s){if(typeof s=="boolean"||s===null)throw new d("Value of anything-but must be an array or single string/number value");if(m(s)){let e=Object.keys(s);if(!e.length)throw new d("Anything-But expression name not found");if(e.length>1)throw new d("Only one key allowed in match expression");let t=e[0];if(t!="prefix")throw new d(`Unsupported anything-but pattern: ${t}`);_(s.prefix)}if(Array.isArray(s)){let e;for(let t of s){let i=typeof t;if(i=="string"||i=="number"){if(e||(e=i),e!=i)throw new d("Inside anything but list, either all values are number or string, mixed type is not supported");continue}throw new d("Inside anything but list, start|null|boolean is not supported")}}}function fe(s){if(!Array.isArray(s))throw new d("Value of numeric must be an array");if(!s.length)throw new d("Invalid member in numeric match");let e=s[0];if(e!="=")throw new d(`Unrecognized numeric range operator: ${e}`);if(e!="="&&!J.includes(e))throw new d(`Unrecognized numeric range operator: ${e}`);if(typeof s[1]!="number")throw new d("Value of equals must be numeric");if(s.length>2){if(e=="=")throw new d("Too many elements in numeric expression");let i=s[2];if(e==i||!J.includes(i)||s.length==3)throw new d(`Bad numeric range operator: ${i}`);if(typeof s[4]!="number")throw new d(`Value of ${i} must be numeric`);if(s.length!=4)throw new d("Too many terms in numeric range expression")}}function ge(s){if(typeof s!="string")throw new d("cidr match pattern must be a string");if(!ce.test(s))throw s.includes("/")?new d("Malformed CIDR"):new d("Malformed CIDR, one '/' required")}function he(s,e){switch(s){case"exists":ue(e);break;case"numeric":fe(e);break;case"anything-but":de(e);break;case"equals-ignore-case":le(e);break;case"prefix":_(e);break;case"suffix":pe(e);break;case"cidr":ge(e);break;default:throw new d(`Unrecognized match type ${s}`)}}function me(s,e,t){let i=0;for(let r of s){if(typeof r=="string"||typeof r=="number"||typeof r=="boolean"||r===null){i++;continue}if(Array.isArray(r))throw new d("Match value must be String, number, true, false, or null");let n=Object.keys(r);if(!n.length)throw new d("Empty objects are not allowed");if(n.length>1)throw new d("Only one key allowed in match expression");let o=n[0];he(o,r[o]),i++}i&&(e.values=e.values*t*i)}function be(s,e,t){if(s.length<2)throw new d("There must have at least 2 Objects in $or relationship.");let i=e.isTopLevel,r=e.values,n=[];for(let l of s){if(!m(l))throw new d("Only JSON object is allowed in array of $or relationship.");let p=Object.keys(l);if(!p.length)throw new d("Empty objects are not allowed");let f=p.find(g=>ae.includes(g));if(f)throw new d(`${f} is Ruler reserved fieldName which cannot be used inside $or.`);e.isTopLevel=i,e.values=1,q(l,e,t),n.push(e.values)}let o=n.reduce((l,p)=>l+=p,0);e.values=r*o}function q(s,e,t){let i=e.isTopLevel,r=Object.keys(s);if(e.isTopLevel){for(let n of r)n!="$or"&&e.keys.add(n);e.isTopLevel=!1}else e.hasNestedField=!0;for(let[n,o]of Object.entries(s)){if(Array.isArray(o)){if(!o.length)throw new d("Empty arrays are not allowed");n=="$or"?(e.isTopLevel=i,be(o,e,t)):me(o,e,t);continue}if(m(o)){q(o,e,t+1);continue}throw new d(`"${n}" must be an object or an array`)}e.isTopLevel=!1}function B(s){if(Buffer.from(s,"utf-8").byteLength>262144)throw new d("Filter policy too big");let e;try{e=JSON.parse(s)}catch{throw new d("failed to parse JSON")}if(!m(e))throw new d("Filter is not an object");let t={keys:new Set,values:1,isTopLevel:!0,hasNestedField:!1};if(q(e,t,1),t.keys.size>5)throw new d("Filter policy can not have more than 5 keys");if(t.values>150)throw new d("Filter policy is too complex");return{pattern:e,counters:t}}function H(s){let e=B(s);if(e.counters.hasNestedField)throw new d("Filter policy scope MessageAttributes does not support nested filter policy");return e}var N=class{constructor(e,t,i,r,n){this.config=e;this.topicArn=t;this.getLambdas=r;this.getSqsClient=n;this.id=k(),this.arn=`${t}:${this.id}`,this.validateProtocol(),this.validateAttributes(),this.internalAttributes={ConfirmationWasAuthenticated:this.config.Protocol.startsWith("http")?"false":"true",PendingConfirmation:this.config.Protocol.startsWith("http")?"true":"false",Owner:i,SubscriptionPrincipal:`arn:aws:iam::${i}:user/exlo`}}id;arn;deleted=!1;filterPattern;fitlerScope="MessageAttributes";queueName="";lambdaName="";queueUrl;confirmationToken;internalAttributes;validateProtocol(){if(this.config.Protocol=="sqs"){let e=I(this.config.Endpoint);if(!x(e))throw new u("Invalid SQS ARN: Must be an arn string (example: 'arn:aws:sqs:eu-west-1:123456789012:MyQueue')");this.queueName=e.resourceId;return}if(this.config.Protocol=="lambda"){let e=I(this.config.Endpoint);if(!z(e))throw new u("Invalid parameter: Lambda endpoint ARN");this.lambdaName=e.resourceId;return}if(this.config.Protocol=="http"){if(!this.config.Endpoint.startsWith("http://"))throw new u("Invalid parameter: Endpoint must match the specified protocol");return}if(this.config.Protocol=="https"&&!this.config.Endpoint.startsWith("https://"))throw new u("Invalid parameter: Endpoint must match the specified protocol");console.warn("Only SQS, Lambda and HTTP/S Endpoints are currently supported.")}validateAttributes(){if(this.config.Attributes){if("RedrivePolicy"in this.config.Attributes)try{let e=JSON.parse(this.config.Attributes.RedrivePolicy);x(I(e.deadLetterTargetArn))}catch{}if("RawMessageDelivery"in this.config.Attributes){if(!["true","false"].includes(this.config.Attributes.RawMessageDelivery))throw new u(`Invalid parameter: Attributes Reason: RawMessageDelivery: Invalid value [${this.config.Attributes.RawMessageDelivery}]. Must be true or false.`);if(!["sqs","http","https"].includes(this.config.Protocol))throw new u(`Invalid parameter: Attributes Reason: Delivery protocol [${this.config.Protocol}] does not support raw message delivery.`)}if("FilterPolicyScope"in this.config.Attributes){if(!["MessageBody","MessageAttributes"].includes(this.config.Attributes.FilterPolicyScope))throw new u(`Invalid parameter: Attributes Reason: FilterPolicyScope: Invalid value [${this.config.Attributes.FilterPolicyScope}]. Please use either MessageBody or MessageAttributes`);this.fitlerScope=this.config.Attributes.FilterPolicyScope}if(this.config.Attributes.FilterPolicy)if(this.fitlerScope=="MessageAttributes"){let{pattern:e}=H(this.config.Attributes.FilterPolicy);this.filterPattern=e}else{let{pattern:e}=B(this.config.Attributes.FilterPolicy);this.filterPattern=e}}}async notify(e){let t=e.message;if(e.messageStructure=="json"){if(t=e.defaultMessage,this.config.Protocol=="sqs"){if(e.sqsMessage=="")return;e.sqsMessage&&(t=e.sqsMessage)}else if(this.config.Protocol=="http"){if(e.httpMessage=="")return;e.httpMessage&&(t=e.httpMessage)}else if(this.config.Protocol=="https"){if(e.httpsMessage=="")return;e.httpsMessage&&(t=e.httpsMessage)}else if(this.config.Protocol=="lambda"){if(e.lambdaMessage=="")return;e.lambdaMessage&&(t=e.lambdaMessage)}}if(!this.shouldNotify(e.messageAttributes,t))return;let i={};for(let[n,o]of Object.entries(e.messageAttributes))this.config.Protocol=="lambda"?o.Type.startsWith("String")||o.Type.startsWith("Number")?i[n]={Type:"String",Value:o.Value}:o.Type.startsWith("Binary")?i[n]={Type:"Binary",Value:o.Value}:i[n]={Type:o.Type,Value:o.Value}:i[n]={Type:o.Type,Value:o.Value};let r={Type:"Notification",MessageId:e.messageId,TopicArn:this.topicArn,Message:t,Timestamp:e.timestamp,UnsubscribeUrl:`${e.serverHost}/?Action=Unsubscribe&SubscriptionArn=${this.arn}`,MessageAttributes:i};this.config.Protocol=="lambda"?(r.SignatureVersion="1",r.Signature="fakeandinvalidsignature",r.SigningCertUrl=`${e.serverHost}/SimpleNotificationService-fakecert.pem`,e.subject?r.Subject=e.subject:r.Subject=null,await this.notifyLambda(r)):this.config.Protocol=="sqs"?(e.subject&&(r.Subject=e.subject),await this.notifySqs(r,e)):(this.config.Protocol=="http"||this.config.Protocol=="https")&&(e.subject&&(r.Subject=e.subject),await this.notifyHttp(r))}getAttributes(){return{...this.config.Attributes,...this.internalAttributes,Endpoint:this.config.Endpoint,Protocol:this.config.Protocol,SubscriptionArn:this.arn}}shouldNotify(e,t){if(this.internalAttributes.PendingConfirmation!="true"){if(!this.filterPattern)return!0;if(this.fitlerScope=="MessageAttributes"){let i={};for(let[r,n]of Object.entries(e)){if(n.Type.startsWith("Binary."))return!1;if(!n.Type.startsWith("Binary")){if(n.Type.startsWith("Number")){i[r]=Number(n.Value);continue}if(n.Type=="String.Array")try{i[r]=JSON.parse(n.Value);continue}catch{}n.Type.startsWith("String")&&(i[r]=n.Value)}}return A(this.filterPattern,i)}if(!t)return!1;try{let i=JSON.parse(t);return m(i)?A(this.filterPattern,i):!1}catch{return!1}}}async notifyLambda(e){let t=this.getLambdas().find(r=>r.name==this.lambdaName);if(!t)return;let i={Records:[{EventSource:"aws:sns",EventVersion:"1.0",EventSubscriptionArn:this.arn,Sns:e}]};await t.invoke(i)}async getQueueUrl(){if(!this.queueUrl){let e=this.getSqsClient(),{QueueUrl:t}=await e.getQueueUrl({QueueName:this.queueName});this.queueUrl=t}return this.queueUrl}async notifyHttp(e){let t={"content-type":"text/plain; charset=UTF-8","user-agent":"Amazon Simple Notification Service Agent","x-amz-sns-subscription-arn":this.arn,"x-amz-sns-message-type":"Notification","x-amz-sns-message-id":e.MessageId,"x-amz-sns-topic-arn":this.topicArn},i;if(this.config.Attributes?.RawMessageDelivery=="true")i=e.Message,t["x-amz-sns-rawdelivery"]="true";else{let r=Object.keys(e.MessageAttributes).length;i=JSON.stringify({...e,MessageAttributes:r?e.MessageAttributes:void 0})}try{await K(this.config.Endpoint,{method:"POST",body:i,headers:t},3)}catch{console.error(`Unable to publish SNS Message for Endpoint: ${this.config.Endpoint}`)}}async notifySqs(e,t){let i=this.getSqsClient(),r=await this.getQueueUrl(),n={QueueUrl:r,MessageAttributes:{}};if(this.config.Attributes?.RawMessageDelivery=="true"){n.MessageBody=e.Message;let o=0;for(let[l,p]of Object.entries(e.MessageAttributes))o++,n.MessageAttributes[l]={DataType:p.Type},p.Type.startsWith("Binary")?n.MessageAttributes[l].BinaryValue=Buffer.from(p.Value,"base64"):n.MessageAttributes[l].StringValue=p.Value;if(o>10)throw new a({Code:"ServiceError",Message:"Can not send more than 10 message attributes to SQS endpoint with RawMessageDelivery enabled"})}else n.MessageBody=JSON.stringify(e);t.messageGroupId&&(n.MessageGroupId=t.messageGroupId),r.endsWith(".fifo")&&(n.MessageDeduplicationId=t.messageDeduplicationId),await i.sendMessage(n)}async redrive(){}requestConfirmation(e){if(!["http","https"].includes(this.config.Protocol))return;let t=k(),i=Buffer.from(JSON.stringify({u:k(),a:this.arn,d:Date.now()})).toString("base64url"),r=JSON.stringify({Type:"SubscriptionConfirmation",MessageId:t,Token:i,TopicArn:this.topicArn,Message:`You have chosen to subscribe to the topic ${this.topicArn}.
31
+ To confirm the subscription, visit the SubscribeURL included in this message.`,SubscribeURL:`${e}/?Action=ConfirmSubscription&TopicArn=${this.topicArn}&Token=${i}`,Timestamp:new Date().toISOString(),SignatureVersion:"1",Signature:"fakeandinvalidsignature",SigningCertURL:`${e}/SimpleNotificationService-fakecert.pem`}),n=this.config,o=this.internalAttributes;this.confirmationToken=i,K(this.config.Endpoint,{method:"POST",body:r,headers:{"x-amz-sns-message-id":t,"x-amz-sns-topic-arn":this.topicArn,"user-agent":"Amazon Simple Notification Service Agent","x-amz-sns-message-type":"SubscriptionConfirmation"}}).then(()=>{o.ConfirmationWasAuthenticated="true"}).catch(()=>{console.error(`Unable to request SNS Confirmation for Endpoint: ${n.Endpoint}`)})}confirm(){this.internalAttributes.PendingConfirmation="false"}};async function K(s,e={},t=30,i=1e3){let r=0;for(;r<=t;)try{let n=await fetch(s,e);if(n.ok)return n;throw new Error(`Non-200 response: ${n.statusText}`)}catch(n){if(r<t)await ye(i),r++;else throw new Error(`Failed after ${t} attempts: ${String(n)}`)}throw new Error("Unknown error.")}import{randomUUID as Se}from"node:crypto";import{createHash as we}from"node:crypto";var Ie=s=>we("sha256").update(s).digest("hex"),V=class{policy={http:{defaultHealthyRetryPolicy:{minDelayTarget:20,maxDelayTarget:20,numRetries:3,numMaxDelayRetries:0,numNoDelayRetries:0,numMinDelayRetries:0,backoffFunction:"linear"},disableSubscriptionOverrides:!1,defaultRequestPolicy:{headerContentType:"text/plain; charset=UTF-8"}}};toString(){return JSON.stringify(this.policy)}},F=class{constructor(e,t){this.topicArn=e;this.accountId=t;this.policy={Version:"2008-10-17",Id:"__default_policy_ID",Statement:[{Sid:"__default_statement_ID",Effect:"Allow",Principal:{AWS:"*"},Action:["SNS:GetTopicAttributes","SNS:SetTopicAttributes","SNS:AddPermission","SNS:RemovePermission","SNS:DeleteTopic","SNS:Subscribe","SNS:ListSubscriptionsByTopic","SNS:Publish"],Resource:this.topicArn,Condition:{StringEquals:{"AWS:SourceOwner":this.accountId}}}]}}policy;toString(){return JSON.stringify(this.policy)}},P=class{constructor(e,t,i,r){this.config=e;this.serverHost=t;this.region=i;this.accountId=r;this.validateTopic(),this.setTopicDefaultAttributes(),this.TopicArn=`arn:aws:sns:${this.region}:${this.accountId}:${this.config.Name}`,this.internalAttributes={Policy:new F(this.TopicArn,r),EffectiveDeliveryPolicy:new V,Owner:this.accountId,TopicArn:this.TopicArn}}internalAttributes;TopicArn;subscribers=[];sequenceNumber=0;getAttributes(){let e=0,t=0,i=0;for(let n of this.subscribers){if(n.deleted){t++;continue}n.internalAttributes.PendingConfirmation=="true"?i++:e++}return{...this.config.Attributes,...this.internalAttributes,SubscriptionsConfirmed:e,SubscriptionsDeleted:t,SubscriptionsPending:i}}setTopicDefaultAttributes(){this.config.Attributes??={},this.config.Attributes.DisplayName||(this.config.Attributes.DisplayName=""),this.config.Attributes.TracingConfig||(this.config.Attributes.TracingConfig="PassThrough"),this.config.Attributes.SignatureVersion||(this.config.Attributes.SignatureVersion="1"),this.config.Attributes.FifoTopic?(this.config.Attributes.ContentBasedDeduplication==null&&(this.config.Attributes.ContentBasedDeduplication=!1),this.config.Attributes.FifoThroughputScope||(this.config.Attributes.FifoThroughputScope="Topic")):this.config.Attributes.FifoTopic=!1}validateTopic(){if(!this.isValidSnsTopicName(this.config.Name))throw new u("Invalid parameter: Topic Name");if(this.config.Name.endsWith(".fifo")&&!this.config.Attributes?.FifoTopic||this.config.Attributes?.FifoTopic&&!this.config.Name.endsWith(".fifo"))throw new u("Invalid parameter: Topic Name");if(this.config.Attributes?.TracingConfig!=null&&!["PassThrough","Active"].includes(this.config.Attributes?.TracingConfig))throw new u(`Attributes Reason: Invalid tracing config value: ${this.config.Attributes?.TracingConfig}`);this.config.Name.endsWith(".fifo")?this.validateFifoTopic():this.validateStandartTopic()}isValidSnsTopicName(e){return!(e.length<1||e.length>256||!/^[A-Za-z0-9_-]+(\.fifo)?$/.test(e)||e.endsWith(".fifo")&&e.slice(0,-5).length<1)}validateFifoTopic(){}validateStandartTopic(){if(this.config.Attributes){if("ContentBasedDeduplication"in this.config.Attributes)throw new u("Attributes Reason: Unknown attribute ContentBasedDeduplication");if("ArchivePolicy"in this.config.Attributes)throw new u("Attributes Reason: Unknown attribute ArchivePolicy");if("FifoThroughputScope"in this.config.Attributes)throw new u("Attributes Reason: Unknown attribute FifoThroughputScope")}}getSequenceNumber(){return this.sequenceNumber++,`1${`${this.sequenceNumber}000`.padStart(19,"0")}`}validateMsg(e){if(e.messageSize>262144)throw new a({Code:"InvalidParameter",Message:"Invalid parameter: Message too long"});if(this.config.Name.endsWith(".fifo")){if(!e.messageGroupId)throw new a({Code:"InvalidParameter",Message:"Invalid parameter: The MessageGroupId parameter is required for FIFO topics"});if(!e.messageDeduplicationId)throw new a({Code:"InvalidParameter",Message:"Invalid parameter: The topic should either have ContentBasedDeduplication enabled or MessageDeduplicationId provided explicitly"})}else{if(e.messageGroupId)throw new a({Code:"InvalidParameter",Message:"Invalid parameter: MessageGroupId Reason: The request includes MessageGroupId parameter that is not valid for this topic type"});if(e.messageDeduplicationId)throw new a({Code:"InvalidParameter",Message:"Invalid parameter: MessageDeduplicationId Reason: The request includes MessageDeduplicationId parameter that is not valid for this topic type"})}}createTopicMessage(e){let t=Se(),i={...e,messageId:t,timestamp:new Date().toISOString(),serverHost:this.serverHost};return this.config.Name.endsWith(".fifo")&&this.config.Attributes?.ContentBasedDeduplication&&(i.messageDeduplicationId||(i.messageDeduplicationId=Ie(i.message))),this.validateMsg(i),i}publish(e){let t=this.createTopicMessage(e),i=this.config.Name.endsWith(".fifo")?this.getSequenceNumber():void 0;for(let r of this.subscribers)r.deleted||r.notify(t).catch(n=>{console.error(n)});return{messageId:t.messageId,sequenceNumber:i}}publishBatchFifo(e){let t=[];for(let r of e.parsedMessages)t.push({id:r.Id,msg:this.createTopicMessage({...r.message,topicArn:e.topicArn,topicName:e.topicName})});let i=[];for(let r of t){i.push({Id:r.id,MessageId:r.msg.messageId,SequenceNumber:this.getSequenceNumber()});for(let n of this.subscribers)n.deleted||n.notify(r.msg).catch(o=>{console.error(o)})}return{successful:i,failed:[]}}publishBatch(e){if(e.parsedMessages.reduce((r,n)=>r+n.message.messageSize,0)>262144)throw new a({Code:"InvalidParameter",Message:"Invalid parameter: Message too long"});if(this.config.Name.endsWith(".fifo"))return this.publishBatchFifo(e);let i={successful:[],failed:[]};for(let r of e.parsedMessages)try{let{messageId:n}=this.publish({...r.message,topicArn:e.topicArn,topicName:e.topicName});i.successful.push({Id:r.Id,MessageId:n})}catch(n){n instanceof a?i.failed.push({Id:r.Id,Code:n.Code,Message:n.message,SenderFault:n.SenderFault}):i.failed.push({Id:r.Id,Code:"UnexpectedError",Message:n?.toString?.()??"Unknown error",SenderFault:!1})}return i}subscribe(e){let t=e.config.Endpoint=="sqs"&&e.config.Endpoint.endsWith(".fifo");if(this.config.Name.endsWith(".fifo")){if(!t)throw new u("Only FIFO SQS is allowed to subscribe to FIFO Topic.")}else if(t)throw new u("FIFO SQS is not allowed to subscribe to Standart Topic.");this.subscribers.push(e)}};var E=class s{constructor(e,t,i,r,n){this.port=e;this.region=t;this.accountId=i;this.getLambdas=r;this.getSqsClient=n}server;topics=[];async start(){this.server=Ae((e,t)=>{this.requestHandler(e,t)}),await new Promise(e=>{this.server.listen(this.port,e)}),this.port=this.server.address().port,this.server.unref()}createTopic(e){let t=new P(e,`http://localhost:${this.port}`,this.region,this.accountId),i=this.topics.find(r=>r.config.Name==e.Name);if(!i)return this.topics.push(t),t;if(!ve(t.config,i.config))throw new u("Attributes Reason: Topic already exists with different attributes");return i}subscribe(e,t){let i=e.subscribers.find(n=>n.config.Endpoint==t.Endpoint&&!n.deleted);if(i)return i;let r=new N(t,e.TopicArn,this.accountId,this.getLambdas,this.getSqsClient);return e.subscribe(r),r}stop(){this.server?.close()}getTopicByName(e){let t=this.topics.find(i=>i.config.Name==e);if(!t)throw new a({Code:"NotFound",Message:"Topic does not exist",statusCode:404});return t}requestSubscriptionsConfirmation(){let e=`http://localhost:${this.port}`;for(let t of this.topics)for(let i of t.subscribers)i.requestConfirmation(e)}static async collectBody(e){let t=Buffer.alloc(0);return e.on("data",i=>{t=Buffer.concat([t,i])}),new Promise(i=>{e.on("end",async()=>{i(t?t.toString("utf-8"):void 0)})})}static async getRequestBody(e){let{method:t,url:i}=e,r;if(t=="GET")try{let n=new URL(i,"http://localhost:300");n.search&&(r=n.search.slice(1))}catch{}else t=="POST"&&(r=await s.collectBody(e));return r}async requestHandler(e,t){let i=C();t.setHeader("x-amzn-requestid",i),t.setHeader("Content-Type","application/xml");let r="";try{let n=await s.getRequestBody(e);if(n){let o=Me(n);switch(typeof o.Action=="string"&&(r=o.Action),r){case"Publish":return this.handlePublishRequest(o,t,i);case"PublishBatch":return this.handlePublishBatchRequest(o,t,i);case"CreateTopic":return this.handleCreateTopicRequest(o,t,i);case"GetTopicAttributes":return this.handleGetTopicAttributes(o,t,i);case"DeleteTopic":return this.handleDeleteTopic(o,t,i);case"ListTopics":return this.handleListTopics(o,t,i);case"Subscribe":return this.handleSubscribe(o,t,i);case"Unsubscribe":return this.handleUnsubscribe(o,t,i);case"ListSubscriptions":return this.handleListSubscriptions(o,t,i);case"ListSubscriptionsByTopic":return this.handleListSubscriptionsByTopic(o,t,i);case"GetSubscriptionAttributes":return this.handleGetSubscriptionAttributes(o,t,i);case"ConfirmSubscription":return this.handleConfirmSubscription(o,t,i);default:break}}}catch(n){n instanceof a?(t.statusCode=n.statusCode,t.end(n.toXml(i))):(t.statusCode=500,t.end(a.genericErrorResponse({Code:"InternalError",RequestId:i,Message:n?.toString?.()??"Unknown error"})));return}t.statusCode=500,t.end(new a({Code:"UnsupportedOperation",Message:`This Action ${r?`(${r})`:""} is currently not supported`}).toXml(i))}handlePublishRequest(e,t,i){let r=L(e),n=this.topics.find(f=>f.config.Name==r.topicName);if(!n)throw new a({Code:"NotFound",Message:"Topic does not exist",statusCode:404});let{messageId:o,sequenceNumber:l}=n.publish(r),p=W(o,i,l);t.statusCode=200,t.end(p)}handlePublishBatchRequest(e,t,i){let r=U(e),n=this.topics.find(p=>p.config.Name==r.topicName);if(!n)throw new a({Code:"NotFound",Message:"Topic does not exist",statusCode:404});let o=n.publishBatch(r),l=Q(i,o.successful,o.failed);t.statusCode=200,t.end(l)}handleCreateTopicRequest(e,t,i){let r=O(e),n=this.createTopic(r);t.statusCode=200,t.end(`<CreateTopicResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
32
+ <CreateTopicResult>
33
+ <TopicArn>arn:aws:sns:${this.region}:${this.accountId}:${n.config.Name}</TopicArn>
34
+ </CreateTopicResult>
35
+ <ResponseMetadata>
36
+ <RequestId>${i}</RequestId>
37
+ </ResponseMetadata>
38
+ </CreateTopicResponse>`)}handleGetTopicAttributes(e,t,i){let{topicName:r}=S(e),o=this.getTopicByName(r).getAttributes(),l=Object.keys(o).map(p=>`<entry><key>${p}</key><value>${o[p]}</value></entry>`).join("");t.end(`<GetTopicAttributesResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
39
+ <GetTopicAttributesResult>
40
+ <Attributes>${l}</Attributes>
41
+ </GetTopicAttributesResult>
42
+ <ResponseMetadata>
43
+ <RequestId>${i}</RequestId>
44
+ </ResponseMetadata>
45
+ </GetTopicAttributesResponse>`)}handleDeleteTopic(e,t,i){let{topicName:r}=S(e),n=this.topics.findIndex(o=>o.config.Name==r);n!=-1&&this.topics.splice(n,1),t.end(`<DeleteTopicResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
46
+ <ResponseMetadata>
47
+ <RequestId>${i}</RequestId>
48
+ </ResponseMetadata>
49
+ </DeleteTopicResponse>`)}handleListTopics(e,t,i){let{NextToken:r}=e,n=0;if(r)try{let f=JSON.parse(Buffer.from(r,"base64").toString()),g=this.topics.findIndex(b=>b.TopicArn==f.t);if(g==-1)throw new Error("Invalid token");n=g}catch{throw new u("Invalid parameter: NextToken")}let o=n+99,l=this.topics.slice(n,o).map(f=>`<member><TopicArn>${f.TopicArn}</TopicArn></member>`).join(""),p="";this.topics.length>o&&(p=`<NextToken>${Buffer.from(JSON.stringify({i:C(),d:Date.now(),t:this.topics[o].TopicArn}),"utf-8").toString("base64")}</NextToken>`),t.end(`<ListTopicsResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
50
+ <ListTopicsResult>
51
+ ${p}
52
+ <Topics>
53
+ ${l}
54
+ </Topics>
55
+ </ListTopicsResult>
56
+ <ResponseMetadata>
57
+ <RequestId>${i}</RequestId>
58
+ </ResponseMetadata>
59
+ </ListTopicsResponse>`)}handleListSubscriptions(e,t,i){let{NextToken:r}=e,n=[];for(let g of this.topics)for(let b of g.subscribers)n.push(b);let o=0;if(r)try{let g=JSON.parse(Buffer.from(r,"base64").toString()),b=n.findIndex(h=>h.arn==g.t);if(b==-1)throw new Error("Invalid token");o=b}catch{throw new u("Invalid parameter: NextToken")}let l=o+99,p=n.slice(o,l).filter(g=>!g.deleted).map(g=>`<member><TopicArn>${g.topicArn}</TopicArn><Protocol>${g.config.Protocol}</Protocol><SubscriptionArn>${g.arn}</SubscriptionArn><Owner>${this.accountId}</Owner><Endpoint>${g.config.Endpoint}</Endpoint></member>`).join(""),f="";n.length>l&&(f=`<NextToken>${Buffer.from(JSON.stringify({i:C(),d:Date.now(),t:n[l].arn}),"utf-8").toString("base64")}</NextToken>`),t.end(`<ListSubscriptionsResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
60
+ <ListSubscriptionsResult>
61
+ ${f}
62
+ <Subscriptions>
63
+ ${p}
64
+ </Subscriptions>
65
+ </ListSubscriptionsResult>
66
+ <ResponseMetadata>
67
+ <RequestId>${i}</RequestId>
68
+ </ResponseMetadata>
69
+ </ListSubscriptionsResponse>`)}handleListSubscriptionsByTopic(e,t,i){let{NextToken:r}=e,{topicName:n}=S(e),l=this.getTopicByName(n).subscribers,p=0;if(r)try{let h=JSON.parse(Buffer.from(r,"base64").toString()),c=l.findIndex(y=>y.arn==h.t);if(c==-1)throw new Error("Invalid token");p=c}catch{throw new u("Invalid parameter: NextToken")}let f=p+99,g=l.slice(p,f).filter(h=>!h.deleted).map(h=>`<member><TopicArn>${h.topicArn}</TopicArn><Protocol>${h.config.Protocol}</Protocol><SubscriptionArn>${h.arn}</SubscriptionArn><Owner>${this.accountId}</Owner><Endpoint>${h.config.Endpoint}</Endpoint></member>`).join(""),b="";l.length>f&&(b=`<NextToken>${Buffer.from(JSON.stringify({i:C(),d:Date.now(),t:l[f].arn}),"utf-8").toString("base64")}</NextToken>`),t.end(`<ListSubscriptionsByTopicResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
70
+ <ListSubscriptionsByTopicResult>
71
+ ${b}
72
+ <Subscriptions>
73
+ ${g}
74
+ </Subscriptions>
75
+ </ListSubscriptionsByTopicResult>
76
+ <ResponseMetadata>
77
+ <RequestId>${i}</RequestId>
78
+ </ResponseMetadata>
79
+ </ListSubscriptionsByTopicResponse>`)}handleSubscribe(e,t,i){let{topicName:r,Endpoint:n,Protocol:o,Attributes:l}=j(e),p=this.getTopicByName(r),f=this.subscribe(p,{Endpoint:n,Protocol:o,Attributes:l});t.end(`<SubscribeResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
80
+ <SubscribeResult>
81
+ <SubscriptionArn>${f.arn}</SubscriptionArn>
82
+ </SubscribeResult>
83
+ <ResponseMetadata>
84
+ <RequestId>${i}</RequestId>
85
+ </ResponseMetadata>
86
+ </SubscribeResponse>`)}handleUnsubscribe(e,t,i){let r=$(e),n=this.topics.find(o=>o.config.Name==r.topicName);if(n){let o=n.subscribers.find(l=>l.id==r.subscriptionId);o&&(o.deleted=!0)}t.end(`<UnsubscribeResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
87
+ <ResponseMetadata>
88
+ <RequestId>${i}</RequestId>
89
+ </ResponseMetadata>
90
+ </UnsubscribeResponse>`)}handleGetSubscriptionAttributes(e,t,i){let r=$(e),n=this.topics.find(f=>f.config.Name==r.topicName);if(!n)throw new a({Code:"NotFound",Message:"Subscription does not exist",statusCode:404});let o=n.subscribers.find(f=>f.id==r.subscriptionId&&!f.deleted);if(!o)throw new a({Code:"NotFound",Message:"Subscription does not exist",statusCode:404});let l=o.getAttributes(),p=Object.keys(l).map(f=>`<entry><key>${f}</key><value>${l[f]}</value></entry>`).join("");t.end(`<GetSubscriptionAttributesResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
91
+ <GetSubscriptionAttributesResult>
92
+ <Attributes>
93
+ ${p}
94
+ </Attributes>
95
+ </GetSubscriptionAttributesResult>
96
+ <ResponseMetadata>
97
+ <RequestId>${i}</RequestId>
98
+ </ResponseMetadata>
99
+ </GetSubscriptionAttributesResponse>`)}handleConfirmSubscription(e,t,i){let{topicName:r}=S(e),n=this.getTopicByName(r);if(!e.Token)throw new u("Invalid token");let o=n.subscribers.find(l=>l.confirmationToken==e.Token);if(!o)throw new u("Invalid token");o.confirm(),t.end(`<ConfirmSubscriptionResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
100
+ <ConfirmSubscriptionResult>
101
+ <SubscriptionArn>${o.arn}</SubscriptionArn>
102
+ </ConfirmSubscriptionResult>
103
+ <ResponseMetadata>
104
+ <RequestId>${i}</RequestId>
105
+ </ResponseMetadata>
106
+ </ConfirmSubscriptionResponse>`)}};var Yt=s=>{let e=0,t=[],i=!0,r=!0;s&&(typeof s.port=="number"&&(e=s.port),Array.isArray(s.topics)&&(t=s.topics),typeof s.setEndpointEnvVar=="boolean"&&(i=s.setEndpointEnvVar),typeof s.enable=="boolean"&&(r=s.enable));let n;return{name:"sns-plugin",shared:{topics:t},async onInit(){if(!r)return;let{region:l,accountId:p}=this.getAwsProviderDefaults(),f=()=>this.lambdas,g=()=>{let h=s?.sqsClient??this.getServices().sqs;if(!h)throw new a({Code:"InternalError",Message:"Dont know how to send SQS message without SQS client. Use SQS Plugin or provide a client in SNS Plugin options. Make sure target SQS exists."});return h};n=new E(e,l,p,f,g),await n.start();for(let h of t){let c=n.createTopic(h);for(let y of h.subscribers){let w=y.Endpoint;typeof y.Endpoint&&!y.Endpoint.startsWith("arn:aws")&&(y.Protocol=="sqs"?w=`arn:aws:sqs:${l}:${p}:${w}`:y.Protocol=="lambda"&&(w=`arn:aws:lambda:${l}:${p}:function:${w}`)),n.subscribe(c,{...y,Endpoint:w})}}let b=`http://localhost:${n.port}`;if(this.log.PINK(`SNS endpoint: ${b}`),this.setEndpoint("sns",b,i?"AWS_ENDPOINT_URL_SNS":void 0),!this.getServices().sns){let h=new Te({endpoint:b,region:l,credentials:{accessKeyId:"test",secretAccessKey:"test"}});this.setService("sns",h)}},onKill(){n?.stop()},server:{onReady(l,p){n?.requestSubscriptionsConfirmation()}}}};export{Yt as snsPlugin};
@@ -0,0 +1,2 @@
1
+ import type { ISnsTopic } from "../topic";
2
+ export declare function parseCreateTopic(body: any): ISnsTopic;
@@ -0,0 +1,18 @@
1
+ export interface UnknownParsedMessage {
2
+ message: string;
3
+ messageSize: number;
4
+ messageStructure?: "json";
5
+ defaultMessage?: string;
6
+ sqsMessage?: string;
7
+ httpMessage?: string;
8
+ httpsMessage?: string;
9
+ lambdaMessage?: string;
10
+ subject: string | null;
11
+ messageAttributes: Record<string, {
12
+ Type: "String" | "Number" | "Binary" | `String.${string}` | `Number.${string}` | `Binary.${string}`;
13
+ Value: string;
14
+ }>;
15
+ messageGroupId?: string;
16
+ messageDeduplicationId?: string;
17
+ }
18
+ export declare const parseMessage: (body: any) => UnknownParsedMessage;
@@ -0,0 +1,6 @@
1
+ import { type UnknownParsedMessage } from "./parseMessage";
2
+ export type ParsedMessage = UnknownParsedMessage & {
3
+ topicName: string;
4
+ topicArn: string;
5
+ };
6
+ export declare const parsePublishMessage: (body: any) => ParsedMessage;
@@ -0,0 +1,9 @@
1
+ import { type UnknownParsedMessage } from "./parseMessage";
2
+ export declare const parsePublishMessageBatch: (body: any) => {
3
+ topicArn: string;
4
+ topicName: string;
5
+ parsedMessages: {
6
+ Id: string;
7
+ message: UnknownParsedMessage;
8
+ }[];
9
+ };
@@ -0,0 +1,17 @@
1
+ export declare function parseSubscribe(body: any): {
2
+ TopicArn: string;
3
+ topicName: string;
4
+ Protocol: any;
5
+ Endpoint: string;
6
+ ReturnSubscriptionArn: boolean;
7
+ Attributes: {
8
+ DeliveryPolicy?: string;
9
+ FilterPolicy?: string;
10
+ FilterPolicyScope?: "MessageAttributes" | "MessageBody";
11
+ RawMessageDelivery?: "true" | "false";
12
+ RedrivePolicy?: string;
13
+ ReplayPolicy?: string;
14
+ ReplayStatus?: "Completed" | "In progress" | "Failed" | "Pending";
15
+ SubscriptionRoleArn?: string;
16
+ } | undefined;
17
+ };
@@ -0,0 +1,6 @@
1
+ export declare function parseSubscriptionArn(body: any): {
2
+ topicArn: string;
3
+ topicName: string;
4
+ subscriptionId: string;
5
+ SubscriptionArn: string;
6
+ };
@@ -0,0 +1,4 @@
1
+ export declare function parseTopicArn(body: any): {
2
+ topicArn: string;
3
+ topicName: string;
4
+ };
@@ -0,0 +1,36 @@
1
+ import { type Server } from "node:http";
2
+ import type { SQS } from "@aws-sdk/client-sqs";
3
+ import type { ILambda } from "../../defineConfig";
4
+ import { type ISnsTopicSubscriber, SnsSubscriber } from "./subscriber";
5
+ import { type ISnsTopic, SnsTopic } from "./topic";
6
+ export declare class SnsServer {
7
+ port: number;
8
+ region: string;
9
+ accountId: string;
10
+ private getLambdas;
11
+ private getSqsClient;
12
+ server?: Server;
13
+ private topics;
14
+ constructor(port: number, region: string, accountId: string, getLambdas: () => ILambda[], getSqsClient: () => SQS);
15
+ start(): Promise<void>;
16
+ createTopic(config: ISnsTopic): SnsTopic;
17
+ subscribe(topic: SnsTopic, config: ISnsTopicSubscriber): SnsSubscriber;
18
+ stop(): void;
19
+ getTopicByName(topicName: string): SnsTopic;
20
+ requestSubscriptionsConfirmation(): void;
21
+ private static collectBody;
22
+ private static getRequestBody;
23
+ private requestHandler;
24
+ private handlePublishRequest;
25
+ private handlePublishBatchRequest;
26
+ private handleCreateTopicRequest;
27
+ private handleGetTopicAttributes;
28
+ private handleDeleteTopic;
29
+ private handleListTopics;
30
+ private handleListSubscriptions;
31
+ private handleListSubscriptionsByTopic;
32
+ private handleSubscribe;
33
+ private handleUnsubscribe;
34
+ private handleGetSubscriptionAttributes;
35
+ private handleConfirmSubscription;
36
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ import type { SQS } from "@aws-sdk/client-sqs";
2
+ import type { ILambda } from "../../../defineConfig";
3
+ import type { TopicMessage } from "../topic";
4
+ export interface ISnsTopicSubscriber {
5
+ Attributes?: {
6
+ /** @deprecated not supported */
7
+ DeliveryPolicy?: string;
8
+ FilterPolicy?: string;
9
+ /** @default "MessageAttributes" */
10
+ FilterPolicyScope?: "MessageAttributes" | "MessageBody";
11
+ /**
12
+ * Only for SQS and HTTP/S Protocols
13
+ *
14
+ * @default "false"
15
+ */
16
+ RawMessageDelivery?: "true" | "false";
17
+ RedrivePolicy?: string;
18
+ /** @deprecated currently not supported */
19
+ ReplayPolicy?: string;
20
+ /** @deprecated currently not supported */
21
+ ReplayStatus?: "Completed" | "In progress" | "Failed" | "Pending";
22
+ /** @deprecated currently not supported */
23
+ SubscriptionRoleArn?: string;
24
+ };
25
+ Protocol: "sqs" | "lambda" | "http" | "https";
26
+ Endpoint: string;
27
+ }
28
+ export declare class SnsSubscriber {
29
+ config: ISnsTopicSubscriber;
30
+ topicArn: string;
31
+ private getLambdas;
32
+ private getSqsClient;
33
+ id: string;
34
+ arn: string;
35
+ deleted: boolean;
36
+ private filterPattern?;
37
+ private fitlerScope;
38
+ private queueName;
39
+ private lambdaName;
40
+ private queueUrl?;
41
+ confirmationToken?: string;
42
+ internalAttributes: {
43
+ SubscriptionPrincipal: string;
44
+ Owner: string;
45
+ PendingConfirmation: "true" | "false";
46
+ ConfirmationWasAuthenticated: "true" | "false";
47
+ };
48
+ constructor(config: ISnsTopicSubscriber, topicArn: string, ownerId: string, getLambdas: () => ILambda[], getSqsClient: () => SQS);
49
+ private validateProtocol;
50
+ private validateAttributes;
51
+ notify(msg: TopicMessage): Promise<void>;
52
+ getAttributes(): Record<string, string>;
53
+ private shouldNotify;
54
+ private notifyLambda;
55
+ private getQueueUrl;
56
+ private notifyHttp;
57
+ private notifySqs;
58
+ private redrive;
59
+ requestConfirmation(serverHost: string): void;
60
+ confirm(): void;
61
+ }
@@ -0,0 +1,91 @@
1
+ import { type BinaryLike } from "node:crypto";
2
+ import type { UnknownParsedMessage } from "./parsers/parseMessage";
3
+ import type { ParsedMessage } from "./parsers/parsePublishMessage";
4
+ import type { SnsSubscriber } from "./subscriber";
5
+ export declare const sha256: (contents: string | BinaryLike) => string;
6
+ export type TopicMessage = ParsedMessage & {
7
+ messageId: string;
8
+ timestamp: string;
9
+ serverHost: string;
10
+ };
11
+ export interface TopicBatchMessage {
12
+ topicArn: string;
13
+ topicName: string;
14
+ parsedMessages: {
15
+ Id: string;
16
+ message: UnknownParsedMessage;
17
+ }[];
18
+ }
19
+ interface IPublishBatchResponse {
20
+ successful: {
21
+ Id: string;
22
+ MessageId: string;
23
+ SequenceNumber?: string;
24
+ }[];
25
+ failed: {
26
+ Id: string;
27
+ Code: string;
28
+ Message: string;
29
+ SenderFault: boolean;
30
+ }[];
31
+ }
32
+ export interface ISnsTopic {
33
+ Name: string;
34
+ /** @deprecated currently not supported */
35
+ DataProtectionPolicy?: string;
36
+ Attributes?: {
37
+ /** @deprecated currently not supported */
38
+ DeliveryPolicy?: string;
39
+ DisplayName?: string;
40
+ FifoTopic?: boolean;
41
+ SignatureVersion?: "1" | "2";
42
+ /**
43
+ * @default "PassThrough"
44
+ * @deprecated currently not supported
45
+ */
46
+ TracingConfig?: "PassThrough" | "Active";
47
+ /** @deprecated not supported */
48
+ KmsMasterKeyId?: string;
49
+ /** @deprecated currently not supported */
50
+ ArchivePolicy?: string;
51
+ /** @default false */
52
+ ContentBasedDeduplication?: boolean;
53
+ /**
54
+ * @default "Topic"
55
+ * @deprecated currently not supported
56
+ */
57
+ FifoThroughputScope?: "Topic" | "MessageGroup";
58
+ };
59
+ Tags?: {
60
+ Key: string;
61
+ Value: string;
62
+ }[];
63
+ }
64
+ export declare class SnsTopic {
65
+ config: ISnsTopic;
66
+ private serverHost;
67
+ private region;
68
+ private accountId;
69
+ private internalAttributes;
70
+ TopicArn: string;
71
+ subscribers: SnsSubscriber[];
72
+ private sequenceNumber;
73
+ constructor(config: ISnsTopic, serverHost: string, region: string, accountId: string);
74
+ getAttributes(): Record<string, any>;
75
+ private setTopicDefaultAttributes;
76
+ private validateTopic;
77
+ isValidSnsTopicName(topicName: string): boolean;
78
+ private validateFifoTopic;
79
+ private validateStandartTopic;
80
+ private getSequenceNumber;
81
+ private validateMsg;
82
+ private createTopicMessage;
83
+ publish(req: ParsedMessage): {
84
+ messageId: string;
85
+ sequenceNumber: string | undefined;
86
+ };
87
+ private publishBatchFifo;
88
+ publishBatch(req: TopicBatchMessage): IPublishBatchResponse;
89
+ subscribe(sub: SnsSubscriber): void;
90
+ }
91
+ export {};
@@ -0,0 +1,20 @@
1
+ export interface FailedMessage {
2
+ Id: string;
3
+ SenderFault: boolean;
4
+ Code: string;
5
+ Message: string;
6
+ }
7
+ export declare const genSnsPublishResponse: (MessageId: string, RequestId: string, sequenceNumber?: string) => string;
8
+ export declare const genSnsPublishBatchResponse: (RequestId: string, Successful: any[], Failed: FailedMessage[]) => string;
9
+ interface ParsedArn {
10
+ partition: string;
11
+ service: string;
12
+ region: string;
13
+ accountId: string;
14
+ resourceType?: string;
15
+ resourceId: string;
16
+ }
17
+ export declare function parseAwsArn(arn?: any): ParsedArn | null;
18
+ export declare function isValidSqsQueueArn(arn?: ParsedArn | null): boolean;
19
+ export declare function isValidLambdaFunctionArn(arn?: ParsedArn | null): boolean;
20
+ export {};
@@ -0,0 +1,19 @@
1
+ import { SnsErrorInvalidParameter } from "./errors";
2
+ export declare class SnsFilterPolicyError extends SnsErrorInvalidParameter {
3
+ constructor(msg: string);
4
+ }
5
+ interface IFilterCounter {
6
+ keys: Set<string>;
7
+ values: number;
8
+ isTopLevel: boolean;
9
+ hasNestedField: boolean;
10
+ }
11
+ export declare function validateFilterPolicy(policy: string): {
12
+ pattern: Record<string, any>;
13
+ counters: IFilterCounter;
14
+ };
15
+ export declare function validateFilterPolicyAttributeScope(policy: string): {
16
+ pattern: Record<string, any>;
17
+ counters: IFilterCounter;
18
+ };
19
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import { type ISqsServerOptions } from "local-aws-sqs";
2
+ import type { ExloPlugin } from "../../defineConfig";
3
+ export declare const sqsPlugin: (serviceOptions?: Pick<ISqsServerOptions, "emulateLazyQueues" | "emulateQueueCreationLifecycle" | "validateDlqDestination" | "queues"> & {
4
+ port?: number;
5
+ /**
6
+ * Set `AWS_ENDPOINT_URL_SQS` env variable inside lambdas
7
+ * @default true
8
+ */
9
+ setEndpointEnvVar?: boolean;
10
+ /** @default true */
11
+ enable?: boolean;
12
+ }) => ExloPlugin<{
13
+ isReady: boolean;
14
+ port?: number;
15
+ onReady: (cb: Function) => void;
16
+ }>;
@@ -0,0 +1 @@
1
+ import{SQS as q}from"@aws-sdk/client-sqs";import{createSqsServer as b}from"local-aws-sqs";var E=e=>{let o,s,u=!1,i=!1,f=!1,d=0,y=!0,c=!0,p=[];e&&(typeof e.validateDlqDestination=="boolean"&&(u=e.validateDlqDestination),typeof e.emulateQueueCreationLifecycle=="boolean"&&(i=e.emulateQueueCreationLifecycle),typeof e.emulateLazyQueues=="boolean"&&(f=e.emulateLazyQueues),Array.isArray(e.queues)&&(p=e.queues),typeof e.port=="number"&&(d=e.port),typeof e.setEndpointEnvVar=="boolean"&&(y=e.setEndpointEnvVar),typeof e.enable=="boolean"&&(c=e.enable));let m=[],S=async()=>{a.shared.isReady=!0;for(let t of m)try{await t()}catch{}},n,a={name:"sqs-plugin",shared:{isReady:!1,onReady:t=>{typeof t=="function"?m.push(t):console.warn("onReady callback must be a function")}},onInit:async function(){if(!c)return;let t=this.getAwsProviderDefaults();t.region&&(o=t.region),t.accountId&&(s=t.accountId),n=await b({port:d,region:o,accountId:s,validateDlqDestination:u,emulateQueueCreationLifecycle:i,emulateLazyQueues:f,queues:p}),n.unref();let r=n.address().port;a.shared.port=r;let l=`http://localhost:${r}`;this.getServices().sqs||this.setService("sqs",new q({region:o,endpoint:l,credentials:{accessKeyId:"test",secretAccessKey:"test"}})),this.setEndpoint("sqs",l,y?"AWS_ENDPOINT_URL_SQS":void 0),this.log.PINK(`SQS endpoint: ${l}`),S()},onKill(){n?.close()}};return a};export{E as sqsPlugin};
@@ -0,0 +1,11 @@
1
+ interface Attributes {
2
+ DelaySeconds?: number;
3
+ MessageRetentionPeriod?: number;
4
+ ReceiveMessageWaitTimeSeconds?: number;
5
+ VisibilityTimeout?: number;
6
+ }
7
+ export interface QueueAttributes {
8
+ default?: Attributes;
9
+ override?: Attributes;
10
+ }
11
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { ILambda } from "../../defineConfig";
2
+ import type { QueueAttributes } from "./types";
3
+ export declare const getQueues: (resources: any, lambdas: ILambda[], attributes?: QueueAttributes) => {
4
+ QueueName: string;
5
+ tags?: Record<string, any>;
6
+ Attributes?: Record<string, any>;
7
+ }[];
@@ -0,0 +1,6 @@
1
+ import type { Vitest } from "vitest/node";
2
+ import type { BaseCoverageProvider } from "vitest/coverage";
3
+ export declare function initMonocart(): Promise<void>;
4
+ export declare function generateLambdaCoverage(vitest: Vitest, coverageMap: any, rawCoverageDir: string): Promise<void>;
5
+ export declare function enhanceCoverageProvider(vitest: Vitest, coverageMaps: any[]): Promise<void>;
6
+ export declare function getBaseCoverageProvider(): Promise<BaseCoverageProvider<any>>;
@@ -0,0 +1,29 @@
1
+ import { type ServerOptions } from "exlo";
2
+ import type { Vite } from "vitest/node";
3
+ export interface IVitestPluginOptions {
4
+ /**
5
+ * @default "failed-only"
6
+ */
7
+ reRunOnRebuild?: "failed-only" | "all" | "never";
8
+ rawCoverageDir?: string;
9
+ }
10
+ export declare function exloVitestPlugin(appOptions: ServerOptions | string, testOptions?: IVitestPluginOptions): Vite.Plugin;
11
+ export interface ExloVitestProvidedContext {
12
+ endpoints: {
13
+ lambda: string;
14
+ sns?: string;
15
+ sqs?: string;
16
+ s3?: string;
17
+ } & Record<string, string>;
18
+ restApiGateways?: {
19
+ [id: string]: {
20
+ port: number;
21
+ stage: string;
22
+ };
23
+ };
24
+ }
25
+ declare module "vitest" {
26
+ interface ProvidedContext {
27
+ exlo: ExloVitestProvidedContext;
28
+ }
29
+ }
@@ -0,0 +1 @@
1
+ var V=Object.defineProperty;var b=(t,e)=>()=>(t&&(e=t(t=0)),e);var E=(t,e)=>{for(var r in e)V(t,r,{get:e[r],enumerable:!0})};var h={};E(h,{enhanceCoverageProvider:()=>B,generateLambdaCoverage:()=>M,getBaseCoverageProvider:()=>N,initMonocart:()=>A});import{readFile as I,rm as F}from"node:fs/promises";import{createRequire as O}from"node:module";import m from"node:path";import{fileURLToPath as S}from"node:url";async function A(){if(u)return;let{CoverageReport:t}=await import(j);u=t}async function M(t,e,r){if(!u)return;let s=m.join(r,"generated"),l=new u({name:"exlo coverage report",dataDir:r,outputDir:s,reports:["json"],cleanCache:!0,clean:!0,v8Ignore:!0,sourceFilter:o=>t.coverageProvider.testExclude.shouldInstrument(o),entryFilter:o=>{let n=o.url.startsWith("file:")?S(o.url):o.url;return!t.coverageProvider.testExclude.shouldInstrument(n)}});try{await l.generate();let o=m.join(s,"coverage-final.json"),n=JSON.parse(await I(o,"utf-8"));for(let i of Object.keys(n)){let a=m.join(process.cwd(),i);if(!t.coverageProvider.testExclude.shouldInstrument(a))continue;let c=n[i];c.path=a,e.addFileCoverage(c)}await F(r,{force:!0,recursive:!0})}catch(o){console.log(o)}}async function B(t,e){let r=q[t.config.coverage.provider],l=(await import(P.resolve(r.importPath)))[r.exportName];l.prototype[y]=l.prototype.createCoverageMap,l.prototype.createCoverageMap=function(...o){let n=this[y](...o);return e.push(n),n}}async function N(){return(await import(P.resolve("vitest/coverage"))).BaseCoverageProvider}var u,j,P,q,y,C=b(()=>{"use strict";j="monocart-coverage-reports",P=O(process.cwd());q={v8:{importPath:"@vitest/coverage-v8/dist/provider.js",exportName:"V8CoverageProvider"},istanbul:{importPath:"@vitest/coverage-istanbul/dist/provider.js",exportName:"IstanbulCoverageProvider"}},y=Symbol()});import{randomUUID as k}from"node:crypto";import x from"node:os";import D from"node:path";import{createAppRunner as T}from"exlo";var R="exlo-vitest-plugin",w=Symbol();function G(t){if(t?.length)return Promise.all(t.map(e=>new Promise(r=>{e.shared.onReady(r)})))}var U=(t,e,r)=>{let s=r?.reRunOnRebuild??"failed-only",l=!1;return{name:R,server:{onReady(o,n){t(this.options.plugins)}},async onInit(){if(l)return;e.onClose(async()=>{await this.stop()});let o=async()=>{if(!e.config.coverage.enabled||e.config.coverage.provider=="custom")return;await e.packageInstaller.ensureInstalled("monocart-coverage-reports",e.config.root,"^2.12.6");let{generateLambdaCoverage:i,enhanceCoverageProvider:a,initMonocart:c,getBaseCoverageProvider:p}=await Promise.resolve().then(()=>(C(),h));await c();let g=await p(),d=r?.rawCoverageDir??D.join(x.tmpdir(),`l${k()}`);g.prototype[w]=g.prototype.readCoverageFiles;let f=[];g.prototype.readCoverageFiles=async function(...v){return await i(e,f[f.length-1],d),this[w](...v)},await a(e,f),process.env.NODE_V8_COVERAGE=x.tmpdir();for(let v of this.lambdas)v.setEnv("NODE_V8_COVERAGE",d);l=!0},n=this.options.plugins?.filter(i=>i&&typeof i=="object"&&i.shared?.onReady&&!i.shared.isReady);await G(n),await o()},async buildCallback(o,n){let i=o.errors.length;if(!n&&i){await e.close();return}if(i||!n)return;await e.cancelCurrentRun("keyboard-input");let a=[];if(s=="failed-only")for(let c of e.state.getFailedFilepaths()){let p=e.getModuleSpecifications(c);a.push(...p)}else s=="all"&&(a=await e.globTestSpecifications());a.length&&await e.rerunTestSpecifications(a)}}};function X(t,e){return{name:R,async configureVitest(r){let s=typeof t=="string"?{config:t}:t,l,o=await new Promise(async a=>{let c=T(s),p=U(a,r.vitest,e);typeof s.config=="string"?c.exlo.onBeforeApplyConfigCallbacks.push(g=>{g.plugins.push(p)}):s.config?s.config.plugins?s.config.plugins.push(p):s.config.plugins=[p]:s.config={plugins:[p]},await c.exlo.start(),await c.waitServer,l=c.exlo.endpoints}),n={endpoints:l},i=o.find(a=>a.name=="rest-api-plugin");if(i?.shared?.gateways){let a=i.shared.gateways;n.restApiGateways={};for(let c of a){let{id:p,port:g,stage:d}=c;n.restApiGateways[p]={port:g,stage:d}}}r.vitest.provide("exlo",n)}}}export{X as exloVitestPlugin};
@@ -0,0 +1,17 @@
1
+ import { ExloApp } from "./main";
2
+ import type { ICommonConfig, ILambdaFunction, ITriggers, ServerOptions } from "./standalone_types";
3
+ export type { ICommonConfig, ITriggers, ServerOptions, ILambdaFunction };
4
+ export interface App {
5
+ port: number;
6
+ url: string;
7
+ endpoints: Record<string, string>;
8
+ kill(): Promise<void>;
9
+ [Symbol.asyncDispose]: () => Promise<void>;
10
+ }
11
+ export declare function run(options?: ServerOptions): Promise<App>;
12
+ export declare function createAppRunner(options?: ServerOptions): {
13
+ listeningPort: number;
14
+ listeningUrl: string;
15
+ exlo: ExloApp;
16
+ waitServer: Promise<unknown>;
17
+ };